Fix integer overflows in PAC parsing

In krb5_parse_pac(), check for buffer counts large enough to threaten
integer overflow in the header length and memory length calculations.
Avoid potential integer overflows when checking the length of each
buffer.  Credit to OSS-Fuzz for discovering one of the issues.

CVE-2022-42898:

In MIT krb5 releases 1.8 and later, an authenticated attacker may be
able to cause a KDC or kadmind process to crash by reading beyond the
bounds of allocated memory, creating a denial of service.  A
privileged attacker may similarly be able to cause a Kerberos or GSS
application service to crash.  On 32-bit platforms, an attacker can
also cause insufficient memory to be allocated for the result,
potentially leading to remote code execution in a KDC, kadmind, or GSS
or Kerberos application server process.  An attacker with the
privileges of a cross-realm KDC may be able to extract secrets from a
KDC process's memory by having them copied into the PAC of a new
ticket.

ticket: 9074 (new)
tags: pullup
target_version: 1.20-next
target_version: 1.19-next

@@ -28,6 +28,8 @@
 #include "int-proto.h"
 #include "authdata.h"

+#define MAX_BUFFERS 4096
+
 /* draft-brezak-win2k-krb-authz-00 */

 /*
@@ -317,6 +319,9 @@ krb5_pac_parse(krb5_context context,
     if (version != 0)
         return EINVAL;

+    if (cbuffers < 1 || cbuffers > MAX_BUFFERS)
+        return ERANGE;
+
     header_len = PACTYPE_LENGTH + (cbuffers * PAC_INFO_BUFFER_LENGTH);
     if (len < header_len)
         return ERANGE;
@@ -349,8 +354,8 @@ krb5_pac_parse(krb5_context context,
             krb5_pac_free(context, pac);
             return EINVAL;
         }
-        if (buffer->Offset < header_len ||
-            buffer->Offset + buffer->cbBufferSize > len) {
+        if (buffer->Offset < header_len || buffer->Offset > len ||
+            buffer->cbBufferSize > len - buffer->Offset) {
             krb5_pac_free(context, pac);
             return ERANGE;
         }


ksmbd: prevent out of bound read for SMB2_TREE_CONNNECT

if Status is not 0 and PathLength is long,
smb_strndup_from_utf16 could make out of bound
read in smb2_tree_connnect.

This bug can lead an oops looking something like:

[ 1553.882047] BUG: KASAN: slab-out-of-bounds in smb_strndup_from_utf16+0x469/0x4c0 [ksmbd]
[ 1553.882064] Read of size 2 at addr ffff88802c4eda04 by task kworker/0:2/42805
...
[ 1553.882095] Call Trace:
[ 1553.882098]  <TASK>
[ 1553.882101]  dump_stack_lvl+0x49/0x5f
[ 1553.882107]  print_report.cold+0x5e/0x5cf
[ 1553.882112]  ? smb_strndup_from_utf16+0x469/0x4c0 [ksmbd]
[ 1553.882122]  kasan_report+0xaa/0x120
[ 1553.882128]  ? smb_strndup_from_utf16+0x469/0x4c0 [ksmbd]
[ 1553.882139]  __asan_report_load_n_noabort+0xf/0x20
[ 1553.882143]  smb_strndup_from_utf16+0x469/0x4c0 [ksmbd]
[ 1553.882155]  ? smb_strtoUTF16+0x3b0/0x3b0 [ksmbd]
[ 1553.882166]  ? __kmalloc_node+0x185/0x430
[ 1553.882171]  smb2_tree_connect+0x140/0xab0 [ksmbd]
[ 1553.882185]  handle_ksmbd_work+0x30e/0x1020 [ksmbd]
[ 1553.882197]  process_one_work+0x778/0x11c0
[ 1553.882201]  ? _raw_spin_lock_irq+0x8e/0xe0
[ 1553.882206]  worker_thread+0x544/0x1180
[ 1553.882209]  ? __cpuidle_text_end+0x4/0x4
[ 1553.882214]  kthread+0x282/0x320
[ 1553.882218]  ? process_one_work+0x11c0/0x11c0
[ 1553.882221]  ? kthread_complete_and_exit+0x30/0x30
[ 1553.882225]  ret_from_fork+0x1f/0x30
[ 1553.882231]  </TASK>

There is no need to check error request validation in server.
This check allow invalid requests not to validate message.

Fixes: e2f34481b24d ("cifsd: add server-side procedures for SMB3")
Cc: stable@vger.kernel.org
Reported-by: zdi-disclosures@trendmicro.com # ZDI-CAN-17818
Signed-off-by: Hyunchul Lee <hyc.lee@gmail.com>
Acked-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>

@@ -90,11 +90,6 @@ static int smb2_get_data_area_len(unsigned int *off, unsigned int *len,
 	*off = 0;
 	*len = 0;

-	/* error reqeusts do not have data area */
-	if (hdr->Status && hdr->Status != STATUS_MORE_PROCESSING_REQUIRED &&
-	    (((struct smb2_err_rsp *)hdr)->StructureSize) == SMB2_ERROR_STRUCTURE_SIZE2_LE)
-		return ret;
-
 	/*
 	 * Following commands have data areas so we have to get the location
 	 * of the data buffer offset and data buffer length for the particular


wifi: wilc1000: validate number of channels

There is no validation of 'e->no_of_channels' which can trigger an
out-of-bounds write in the following 'memset' call. Validate that the
number of channels does not extends beyond the size of the channel list
element.

Signed-off-by: Phil Turnbull <philipturnbull@github.com>
Tested-by: Ajay Kathat <ajay.kathat@microchip.com>
Acked-by: Ajay Kathat <ajay.kathat@microchip.com>
Signed-off-by: Kalle Valo <kvalo@kernel.org>
Link: https://lore.kernel.org/r/20221123153543.8568-5-philipturnbull@github.com

@@ -981,19 +981,29 @@ static inline void wilc_wfi_cfg_parse_ch_attr(u8 *buf, u32 len, u8 sta_ch)
 	}

 	if (ch_list_idx) {
-		u16 attr_size;
-		struct wilc_ch_list_elem *e;
-		int i;
+		u16 elem_size;

 		ch_list = (struct wilc_attr_ch_list *)&buf[ch_list_idx];
-		attr_size = le16_to_cpu(ch_list->attr_len);
-		for (i = 0; i < attr_size;) {
+		/* the number of bytes following the final 'elem' member */
+		elem_size = le16_to_cpu(ch_list->attr_len) -
+			(sizeof(*ch_list) - sizeof(struct wilc_attr_entry));
+		for (unsigned int i = 0; i < elem_size;) {
+			struct wilc_ch_list_elem *e;
+
 			e = (struct wilc_ch_list_elem *)(ch_list->elem + i);
+
+			i += sizeof(*e);
+			if (i > elem_size)
+				break;
+
+			i += e->no_of_channels;
+			if (i > elem_size)
+				break;
+
 			if (e->op_class == WILC_WLAN_OPERATING_CLASS_2_4GHZ) {
 				memset(e->ch_list, sta_ch, e->no_of_channels);
 				break;
 			}
-			i += e->no_of_channels;
 		}
 	}


ALSA: control: code refactoring for ELEM_READ/ELEM_WRITE operations

ALSA control core handles ELEM_READ/ELEM_WRITE requests within lock
acquisition of a counting semaphore. The lock is acquired in helper
functions in the end of call path before calling implementations of each
driver.

ioctl(2) with SNDRV_CTL_ELEM_READ
...
->snd_ctl_ioctl()
  ->snd_ctl_elem_read_user()
    ->snd_ctl_elem_read()
      ->down_read(controls_rwsem)
      ->snd_ctl_find_id()
      ->struct snd_kcontrol.get()
      ->up_read(controls_rwsem)

ioctl(2) with SNDRV_CTL_ELEM_WRITE
...
->snd_ctl_ioctl()
  ->snd_ctl_elem_write_user()
    ->snd_ctl_elem_write()
      ->down_read(controls_rwsem)
      ->snd_ctl_find_id()
      ->struct snd_kcontrol.put()
      ->up_read(controls_rwsem)

This commit moves the lock acquisition to middle of the call graph to
simplify the helper functions. As a result:

ioctl(2) with SNDRV_CTL_ELEM_READ
...
->snd_ctl_ioctl()
  ->snd_ctl_elem_read_user()
    ->down_read(controls_rwsem)
    ->snd_ctl_elem_read()
      ->snd_ctl_find_id()
      ->struct snd_kcontrol.get()
    ->up_read(controls_rwsem)

ioctl(2) with SNDRV_CTL_ELEM_WRITE
...
->snd_ctl_ioctl()
  ->snd_ctl_elem_write_user()
    ->down_read(controls_rwsem)
    ->snd_ctl_elem_write()
      ->snd_ctl_find_id()
      ->struct snd_kcontrol.put()
    ->up_read(controls_rwsem)

Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>

@@ -881,24 +881,18 @@ static int snd_ctl_elem_read(struct snd_card *card,
 	struct snd_kcontrol *kctl;
 	struct snd_kcontrol_volatile *vd;
 	unsigned int index_offset;
-	int result;

-	down_read(&card->controls_rwsem);
 	kctl = snd_ctl_find_id(card, &control->id);
-	if (kctl == NULL) {
-		result = -ENOENT;
-	} else {
-		index_offset = snd_ctl_get_ioff(kctl, &control->id);
-		vd = &kctl->vd[index_offset];
-		if ((vd->access & SNDRV_CTL_ELEM_ACCESS_READ) &&
-		    kctl->get != NULL) {
-			snd_ctl_build_ioff(&control->id, kctl, index_offset);
-			result = kctl->get(kctl, control);
-		} else
-			result = -EPERM;
-	}
-	up_read(&card->controls_rwsem);
-	return result;
+	if (kctl == NULL)
+		return -ENOENT;
+
+	index_offset = snd_ctl_get_ioff(kctl, &control->id);
+	vd = &kctl->vd[index_offset];
+	if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_READ) && kctl->get == NULL)
+		return -EPERM;
+
+	snd_ctl_build_ioff(&control->id, kctl, index_offset);
+	return kctl->get(kctl, control);
 }

 static int snd_ctl_elem_read_user(struct snd_card *card,
@@ -913,8 +907,11 @@ static int snd_ctl_elem_read_user(struct snd_card *card,

 	snd_power_lock(card);
 	result = snd_power_wait(card, SNDRV_CTL_POWER_D0);
-	if (result >= 0)
+	if (result >= 0) {
+		down_read(&card->controls_rwsem);
 		result = snd_ctl_elem_read(card, control);
+		up_read(&card->controls_rwsem);
+	}
 	snd_power_unlock(card);
 	if (result >= 0)
 		if (copy_to_user(_control, control, sizeof(*control)))
@@ -931,29 +928,28 @@ static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file,
 	unsigned int index_offset;
 	int result;

-	down_read(&card->controls_rwsem);
 	kctl = snd_ctl_find_id(card, &control->id);
-	if (kctl == NULL) {
-		result = -ENOENT;
-	} else {
-		index_offset = snd_ctl_get_ioff(kctl, &control->id);
-		vd = &kctl->vd[index_offset];
-		if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_WRITE) ||
-		    kctl->put == NULL ||
-		    (file && vd->owner && vd->owner != file)) {
-			result = -EPERM;
-		} else {
-			snd_ctl_build_ioff(&control->id, kctl, index_offset);
-			result = kctl->put(kctl, control);
-		}
-		if (result > 0) {
-			struct snd_ctl_elem_id id = control->id;
-			snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &id);
-			result = 0;
-		}
+	if (kctl == NULL)
+		return -ENOENT;
+
+	index_offset = snd_ctl_get_ioff(kctl, &control->id);
+	vd = &kctl->vd[index_offset];
+	if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_WRITE) || kctl->put == NULL ||
+	    (file && vd->owner && vd->owner != file)) {
+		return -EPERM;
 	}
-	up_read(&card->controls_rwsem);
-	return result;
+
+	snd_ctl_build_ioff(&control->id, kctl, index_offset);
+	result = kctl->put(kctl, control);
+	if (result < 0)
+		return result;
+
+	if (result > 0) {
+		struct snd_ctl_elem_id id = control->id;
+		snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &id);
+	}
+
+	return 0;
 }

 static int snd_ctl_elem_write_user(struct snd_ctl_file *file,
@@ -970,8 +966,11 @@ static int snd_ctl_elem_write_user(struct snd_ctl_file *file,
 	card = file->card;
 	snd_power_lock(card);
 	result = snd_power_wait(card, SNDRV_CTL_POWER_D0);
-	if (result >= 0)
+	if (result >= 0) {
+		down_read(&card->controls_rwsem);
 		result = snd_ctl_elem_write(card, file, control);
+		up_read(&card->controls_rwsem);
+	}
 	snd_power_unlock(card);
 	if (result >= 0)
 		if (copy_to_user(_control, control, sizeof(*control)))


eap: tweak conversation tracking to avoid breaking pinfo horribly

Looks like conversation_set_conv_addr_port_endpoints() from 66b441f3d is
designed with this use case in mind.

This should resolve issue #18622

@@ -1778,8 +1778,6 @@ dissect_eap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
   static address null_address = ADDRESS_INIT_NONE;
   static guint8 pae_group_address_mac_addr[6] = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x03 };
   static address pae_group_address = ADDRESS_INIT(AT_ETHER, sizeof(pae_group_address_mac_addr), pae_group_address_mac_addr);
-  packet_info    pinfo_eapol;
-  packet_info    *pinfo_conv;

   col_set_str(pinfo->cinfo, COL_PROTOCOL, "EAP");
   col_clear(pinfo->cinfo, COL_INFO);
@@ -1815,19 +1813,11 @@ dissect_eap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
    * We set the port so the TLS decoder can figure out which side is the server
    */
   if (pinfo->src.type == AT_ETHER) {
-    memcpy(&pinfo_eapol, pinfo, sizeof(packet_info));
-    pinfo_conv = &pinfo_eapol;
     if (eap_code == EAP_REQUEST) {	/* server -> client */
-      copy_address_shallow(&pinfo_conv->src, &null_address);
-      copy_address_shallow(&pinfo_conv->dst, &pae_group_address);
-      pinfo_conv->srcport = 443;
+      conversation_set_conv_addr_port_endpoints(pinfo, &null_address, &pae_group_address, conversation_pt_to_conversation_type(pinfo->ptype), 443, pinfo->destport);
     } else {				/* client -> server */
-      copy_address_shallow(&pinfo_conv->src, &pae_group_address);
-      copy_address_shallow(&pinfo_conv->dst, &null_address);
-      pinfo_conv->destport = 443;
+      conversation_set_conv_addr_port_endpoints(pinfo, &pae_group_address, &null_address, conversation_pt_to_conversation_type(pinfo->ptype), pinfo->srcport, 443);
     }
-  } else {
-    pinfo_conv = pinfo;
   }

   /*
@@ -1836,20 +1826,20 @@ dissect_eap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
    * as offsets for p_get_proto_data/p_add_proto_data and as done for
    * EAPOL above we massage the client port using this too
    */
-  guint32 tls_group = pinfo_conv->curr_proto_layer_num << 16;
+  guint32 tls_group = pinfo->curr_proto_layer_num << 16;
   if (eap_code == EAP_REQUEST) {	/* server -> client */
-    pinfo_conv->destport |= tls_group;
+    conversation_set_conv_addr_port_endpoints(pinfo, &pinfo->src, &pinfo->dst, conversation_pt_to_conversation_type(pinfo->ptype), pinfo->srcport, pinfo->destport | tls_group);
   } else {				/* client -> server */
-    pinfo_conv->srcport |= tls_group;
+    conversation_set_conv_addr_port_endpoints(pinfo, &pinfo->src, &pinfo->dst, conversation_pt_to_conversation_type(pinfo->ptype), pinfo->srcport | tls_group, pinfo->destport);
   }

-  if (PINFO_FD_VISITED(pinfo_conv) || !(eap_code == EAP_REQUEST && tvb_get_guint8(tvb, 4) == EAP_TYPE_ID)) {
-    conversation = find_conversation_pinfo(pinfo_conv, 0);
+  if (PINFO_FD_VISITED(pinfo) || !(eap_code == EAP_REQUEST && tvb_get_guint8(tvb, 4) == EAP_TYPE_ID)) {
+    conversation = find_conversation_pinfo(pinfo, 0);
   }
   if (conversation == NULL) {
-    conversation = conversation_new(pinfo_conv->num, &pinfo_conv->src,
-		      &pinfo_conv->dst, conversation_pt_to_conversation_type(pinfo_conv->ptype),
-		      pinfo_conv->srcport, pinfo_conv->destport, 0);
+    conversation = conversation_new(pinfo->num, &pinfo->src,
+		      &pinfo->dst, conversation_pt_to_conversation_type(pinfo->ptype),
+		      pinfo->srcport, pinfo->destport, 0);
   }

   /*
@@ -2264,23 +2254,23 @@ dissect_eap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
           if (next_tvb) {
             switch (eap_type) {
               case EAP_TYPE_TTLS:
-                tls_set_appdata_dissector(tls_handle, pinfo_conv, diameter_avps_handle);
+                tls_set_appdata_dissector(tls_handle, pinfo, diameter_avps_handle);
                 break;
               case EAP_TYPE_PEAP:
                 p_add_proto_data(pinfo->pool, pinfo, proto_eap, PROTO_DATA_EAP_TVB | tls_group, tvb);
-                tls_set_appdata_dissector(tls_handle, pinfo_conv, peap_handle);
+                tls_set_appdata_dissector(tls_handle, pinfo, peap_handle);
                 break;
               case EAP_TYPE_TEAP:
                 if (outer_tlvs) {	/* https://www.rfc-editor.org/rfc/rfc7170.html#section-4.1 */
                   tvbuff_t *teap_tvb = tvb_new_subset_length(tvb, offset + size - outer_tlvs_length, outer_tlvs_length);
-                  call_dissector(teap_handle, teap_tvb, pinfo_conv, eap_tree);
+                  call_dissector(teap_handle, teap_tvb, pinfo, eap_tree);
                   if (size == outer_tlvs_length) goto skip_tls_dissector;
                   next_tvb = tvb_new_subset_length(next_tvb, 0, size - outer_tlvs_length);
                 }
-                tls_set_appdata_dissector(tls_handle, pinfo_conv, teap_handle);
+                tls_set_appdata_dissector(tls_handle, pinfo, teap_handle);
                 break;
             }
-            call_dissector(tls_handle, next_tvb, pinfo_conv, eap_tree);
+            call_dissector(tls_handle, next_tvb, pinfo, eap_tree);
           }
         }
       }


Avoid integer overflows in SETRANGE and SORT (CVE-2022-35977) (#11720)

Authenticated users issuing specially crafted SETRANGE and SORT(_RO)
commands can trigger an integer overflow, resulting with Redis attempting
to allocate impossible amounts of memory and abort with an OOM panic.

@@ -328,8 +328,10 @@ void sortCommandGeneric(client *c, int readonly) {
     default: vectorlen = 0; serverPanic("Bad SORT type"); /* Avoid GCC warning */
     }

-    /* Perform LIMIT start,count sanity checking. */
-    start = (limit_start < 0) ? 0 : limit_start;
+    /* Perform LIMIT start,count sanity checking.
+     * And avoid integer overflow by limiting inputs to object sizes. */
+    start = min(max(limit_start, 0), vectorlen);
+    limit_count = min(max(limit_count, -1), vectorlen);
     end = (limit_count < 0) ? vectorlen-1 : start+limit_count-1;
     if (start >= vectorlen) {
         start = vectorlen-1;


@@ -2,6 +2,7 @@
 #include "object-store.h"
 #include "repository.h"
 #include "object.h"
+#include "attr.h"
 #include "blob.h"
 #include "tree.h"
 #include "tree-walk.h"
@@ -614,17 +615,22 @@ static int fsck_tree(const struct object_id *tree_oid,
 						 ".gitmodules is a symbolic link");
 		}

+		if (is_hfs_dotgitattributes(name) || is_ntfs_dotgitattributes(name)) {
+			if (!S_ISLNK(mode))
+				oidset_insert(&options->gitattributes_found,
+					      entry_oid);
+			else
+				retval += report(options, tree_oid, OBJ_TREE,
+						 FSCK_MSG_GITATTRIBUTES_SYMLINK,
+						 ".gitattributes is a symlink");
+		}
+
 		if (S_ISLNK(mode)) {
 			if (is_hfs_dotgitignore(name) ||
 			    is_ntfs_dotgitignore(name))
 				retval += report(options, tree_oid, OBJ_TREE,
 						 FSCK_MSG_GITIGNORE_SYMLINK,
 						 ".gitignore is a symlink");
-			if (is_hfs_dotgitattributes(name) ||
-			    is_ntfs_dotgitattributes(name))
-				retval += report(options, tree_oid, OBJ_TREE,
-						 FSCK_MSG_GITATTRIBUTES_SYMLINK,
-						 ".gitattributes is a symlink");
 			if (is_hfs_dotmailmap(name) ||
 			    is_ntfs_dotmailmap(name))
 				retval += report(options, tree_oid, OBJ_TREE,
@@ -1159,38 +1165,70 @@ static int fsck_gitmodules_fn(const char *var, const char *value, void *vdata)
 static int fsck_blob(const struct object_id *oid, const char *buf,
 		     unsigned long size, struct fsck_options *options)
 {
-	struct fsck_gitmodules_data data;
-	struct config_options config_opts = { 0 };
-
-	if (!oidset_contains(&options->gitmodules_found, oid))
-		return 0;
-	oidset_insert(&options->gitmodules_done, oid);
+	int ret = 0;

 	if (object_on_skiplist(options, oid))
 		return 0;

-	if (!buf) {
-		/*
-		 * A missing buffer here is a sign that the caller found the
-		 * blob too gigantic to load into memory. Let's just consider
-		 * that an error.
-		 */
-		return report(options, oid, OBJ_BLOB,
-			      FSCK_MSG_GITMODULES_LARGE,
-			      ".gitmodules too large to parse");
+	if (oidset_contains(&options->gitmodules_found, oid)) {
+		struct config_options config_opts = { 0 };
+		struct fsck_gitmodules_data data;
+
+		oidset_insert(&options->gitmodules_done, oid);
+
+		if (!buf) {
+			/*
+			 * A missing buffer here is a sign that the caller found the
+			 * blob too gigantic to load into memory. Let's just consider
+			 * that an error.
+			 */
+			return report(options, oid, OBJ_BLOB,
+					FSCK_MSG_GITMODULES_LARGE,
+					".gitmodules too large to parse");
+		}
+
+		data.oid = oid;
+		data.options = options;
+		data.ret = 0;
+		config_opts.error_action = CONFIG_ERROR_SILENT;
+		if (git_config_from_mem(fsck_gitmodules_fn, CONFIG_ORIGIN_BLOB,
+					".gitmodules", buf, size, &data, &config_opts))
+			data.ret |= report(options, oid, OBJ_BLOB,
+					FSCK_MSG_GITMODULES_PARSE,
+					"could not parse gitmodules blob");
+		ret |= data.ret;
 	}

-	data.oid = oid;
-	data.options = options;
-	data.ret = 0;
-	config_opts.error_action = CONFIG_ERROR_SILENT;
-	if (git_config_from_mem(fsck_gitmodules_fn, CONFIG_ORIGIN_BLOB,
-				".gitmodules", buf, size, &data, &config_opts))
-		data.ret |= report(options, oid, OBJ_BLOB,
-				   FSCK_MSG_GITMODULES_PARSE,
-				   "could not parse gitmodules blob");
-
-	return data.ret;
+	if (oidset_contains(&options->gitattributes_found, oid)) {
+		const char *ptr;
+
+		oidset_insert(&options->gitattributes_done, oid);
+
+		if (!buf || size > ATTR_MAX_FILE_SIZE) {
+			/*
+			 * A missing buffer here is a sign that the caller found the
+			 * blob too gigantic to load into memory. Let's just consider
+			 * that an error.
+			 */
+			return report(options, oid, OBJ_BLOB,
+					FSCK_MSG_GITATTRIBUTES_LARGE,
+					".gitattributes too large to parse");
+		}
+
+		for (ptr = buf; *ptr; ) {
+			const char *eol = strchrnul(ptr, '\n');
+			if (eol - ptr >= ATTR_MAX_LINE_LENGTH) {
+				ret |= report(options, oid, OBJ_BLOB,
+					      FSCK_MSG_GITATTRIBUTES_LINE_LENGTH,
+					      ".gitattributes has too long lines to parse");
+				break;
+			}
+
+			ptr = *eol ? eol + 1 : eol;
+		}
+	}
+
+	return ret;
 }

 int fsck_object(struct object *obj, void *data, unsigned long size,
@@ -1229,45 +1267,58 @@ int fsck_error_function(struct fsck_options *o,
 	return 1;
 }

-int fsck_finish(struct fsck_options *options)
+static int fsck_blobs(struct oidset *blobs_found, struct oidset *blobs_done,
+		      enum fsck_msg_id msg_missing, enum fsck_msg_id msg_type,
+		      struct fsck_options *options, const char *blob_type)
 {
 	int ret = 0;
 	struct oidset_iter iter;
 	const struct object_id *oid;

-	oidset_iter_init(&options->gitmodules_found, &iter);
+	oidset_iter_init(blobs_found, &iter);
 	while ((oid = oidset_iter_next(&iter))) {
 		enum object_type type;
 		unsigned long size;
 		char *buf;

-		if (oidset_contains(&options->gitmodules_done, oid))
+		if (oidset_contains(blobs_done, oid))
 			continue;

 		buf = read_object_file(oid, &type, &size);
 		if (!buf) {
 			if (is_promisor_object(oid))
 				continue;
 			ret |= report(options,
-				      oid, OBJ_BLOB,
-				      FSCK_MSG_GITMODULES_MISSING,
-				      "unable to read .gitmodules blob");
+				      oid, OBJ_BLOB, msg_missing,
+				      "unable to read %s blob", blob_type);
 			continue;
 		}

 		if (type == OBJ_BLOB)
 			ret |= fsck_blob(oid, buf, size, options);
 		else
-			ret |= report(options,
-				      oid, type,
-				      FSCK_MSG_GITMODULES_BLOB,
-				      "non-blob found at .gitmodules");
+			ret |= report(options, oid, type, msg_type,
+				      "non-blob found at %s", blob_type);
 		free(buf);
 	}

+	oidset_clear(blobs_found);
+	oidset_clear(blobs_done);
+
+	return ret;
+}
+
+int fsck_finish(struct fsck_options *options)
+{
+	int ret = 0;
+
+	ret |= fsck_blobs(&options->gitmodules_found, &options->gitmodules_done,
+			  FSCK_MSG_GITMODULES_MISSING, FSCK_MSG_GITMODULES_BLOB,
+			  options, ".gitmodules");
+	ret |= fsck_blobs(&options->gitattributes_found, &options->gitattributes_done,
+			  FSCK_MSG_GITATTRIBUTES_MISSING, FSCK_MSG_GITATTRIBUTES_BLOB,
+			  options, ".gitattributes");

-	oidset_clear(&options->gitmodules_found);
-	oidset_clear(&options->gitmodules_done);
 	return ret;
 }


@@ -59,6 +59,10 @@ enum fsck_msg_type {
 	FUNC(GITMODULES_URL, ERROR) \
 	FUNC(GITMODULES_PATH, ERROR) \
 	FUNC(GITMODULES_UPDATE, ERROR) \
+	FUNC(GITATTRIBUTES_MISSING, ERROR) \
+	FUNC(GITATTRIBUTES_LARGE, ERROR) \
+	FUNC(GITATTRIBUTES_LINE_LENGTH, ERROR) \
+	FUNC(GITATTRIBUTES_BLOB, ERROR) \
 	/* warnings */ \
 	FUNC(EMPTY_NAME, WARN) \
 	FUNC(FULL_PATHNAME, WARN) \
@@ -133,25 +137,33 @@ struct fsck_options {
 	struct oidset skiplist;
 	struct oidset gitmodules_found;
 	struct oidset gitmodules_done;
+	struct oidset gitattributes_found;
+	struct oidset gitattributes_done;
 	kh_oid_map_t *object_names;
 };

 #define FSCK_OPTIONS_DEFAULT { \
 	.skiplist = OIDSET_INIT, \
 	.gitmodules_found = OIDSET_INIT, \
 	.gitmodules_done = OIDSET_INIT, \
+	.gitattributes_found = OIDSET_INIT, \
+	.gitattributes_done = OIDSET_INIT, \
 	.error_func = fsck_error_function \
 }
 #define FSCK_OPTIONS_STRICT { \
 	.strict = 1, \
 	.gitmodules_found = OIDSET_INIT, \
 	.gitmodules_done = OIDSET_INIT, \
+	.gitattributes_found = OIDSET_INIT, \
+	.gitattributes_done = OIDSET_INIT, \
 	.error_func = fsck_error_function, \
 }
 #define FSCK_OPTIONS_MISSING_GITMODULES { \
 	.strict = 1, \
 	.gitmodules_found = OIDSET_INIT, \
 	.gitmodules_done = OIDSET_INIT, \
+	.gitattributes_found = OIDSET_INIT, \
+	.gitattributes_done = OIDSET_INIT, \
 	.error_func = fsck_error_cb_print_missing_gitmodules, \
 }


Merge v2.39.1.windows.1 (#4219)

This PR takes the embargoed release tag `v2.39.1.windows.1` and merges
it into the `main` branch.

It likely that I messed something up in the order of releasing the
security release and merging the [security
advisory](https://github.com/git-for-windows/git/security/advisories/GHSA-v4px-mx59-w99c).

@@ -1051,6 +1051,14 @@ static inline unsigned long cast_size_t_to_ulong(size_t a)
 	return (unsigned long)a;
 }

+static inline int cast_size_t_to_int(size_t a)
+{
+	if (a > INT_MAX)
+		die("number too large to represent as int on this platform: %"PRIuMAX,
+		    (uintmax_t)a);
+	return (int)a;
+}
+
 /*
  * Limit size of IO chunks, because huge chunks only cause pain.  OS X
  * 64-bit is buggy, returning EINVAL if len >= INT_MAX; and even in


Fix ANSI Escape Sequence Injection vulns via DWARF ##vuln

* Reported by @solid-snail via huntrdev
* BountyID: 583133af-7ae6-4a21-beef-a4b0182cf82e
* Reproducer: dwarf_test_func_patched

@@ -431,6 +431,7 @@ static const ut8 *parse_line_header_source(RBinFile *bf, const ut8 *buf, const u
 	int i = 0;
 	size_t count;
 	const ut8 *tmp_buf = NULL;
+	char *fn = NULL;

 	if (mode == R_MODE_PRINT) {
 		print (" The Directory Table:\n");
@@ -464,10 +465,12 @@ static const ut8 *parse_line_header_source(RBinFile *bf, const ut8 *buf, const u

 	for (i = 0; i < 2; i++) {
 		while (buf + 1 < buf_end) {
-			const char *filename = (const char *)buf;
 			size_t maxlen = R_MIN ((size_t) (buf_end - buf - 1), 0xfff);
 			ut64 id_idx, mod_time, file_len;
-			size_t len = r_str_nlen (filename, maxlen);
+			free (fn);
+			fn = r_str_ndup ((const char *)buf, maxlen);
+			r_str_ansi_strip (fn);
+			size_t len = strlen (fn);

 			if (!len) {
 				buf++;
@@ -512,7 +515,7 @@ static const ut8 *parse_line_header_source(RBinFile *bf, const ut8 *buf, const u
 				}

 				if (hdr->file_names) {
-					hdr->file_names[count].name = r_str_newf("%s/%s", r_str_get (include_dir), filename);
+					hdr->file_names[count].name = r_str_newf("%s/%s", r_str_get (include_dir), fn);
 					hdr->file_names[count].id_idx = id_idx;
 					hdr->file_names[count].mod_time = mod_time;
 					hdr->file_names[count].file_len = file_len;
@@ -525,7 +528,8 @@ static const ut8 *parse_line_header_source(RBinFile *bf, const ut8 *buf, const u
 			}
 			count++;
 			if (mode == R_MODE_PRINT && i) {
-				print ("  %d     %" PFMT64d "       %" PFMT64d "         %" PFMT64d "          %s\n", entry_index++, id_idx, mod_time, file_len, filename);
+				print ("  %d     %" PFMT64d "       %" PFMT64d "         %" PFMT64d "          %s\n",
+						entry_index++, id_idx, mod_time, file_len, fn);
 			}
 		}
 		if (i == 0) {
@@ -544,6 +548,7 @@ static const ut8 *parse_line_header_source(RBinFile *bf, const ut8 *buf, const u
 	}

 beach:
+	free (fn);
 	sdb_free (sdb);

 	return buf;
@@ -677,7 +682,6 @@ static const ut8 *parse_line_header(

 static inline void add_sdb_addrline(Sdb *s, ut64 addr, const char *file, ut64 line, int mode, PrintfCallback print) {
 	const char *p;
-	char *fileline;
 	char offset[SDB_NUM_BUFSZ];
 	char *offset_ptr;

@@ -706,7 +710,10 @@ static inline void add_sdb_addrline(Sdb *s, ut64 addr, const char *file, ut64 li
 #else
 	p = file;
 #endif
-	fileline = r_str_newf ("%s|%"PFMT64d, p, line);
+	char *fileline = r_str_newf ("%s|%"PFMT64d, p, line);
+	r_str_ansi_strip (fileline);
+	r_str_replace_ch (fileline, '\n', 0, true);
+	r_str_replace_ch (fileline, '\t', 0, true);
 	offset_ptr = sdb_itoa (addr, 16, offset, sizeof (offset));
 	sdb_add (s, offset_ptr, fileline, 0);
 	sdb_add (s, fileline, offset_ptr, 0);
@@ -1666,7 +1673,15 @@ static const ut8 *parse_attr_value(const ut8 *obuf, int obuf_len,
 		break;
 	case DW_FORM_string:
 		value->kind = DW_AT_KIND_STRING;
-		value->string.content = *buf ? r_str_ndup ((const char *)buf, buf_end - buf) : NULL;
+		if (*buf) {
+			char *name = r_str_ndup ((const char *)buf, buf_end - buf);
+			r_str_ansi_strip (name);
+			r_str_replace_ch (name, '\n', 0, true);
+			r_str_replace_ch (name, '\t', 0, true);
+			value->string.content = name;
+		} else {
+			value->string.content = NULL;
+		}
 		if (value->string.content) {
 			buf += strlen (value->string.content) + 1;
 		}
@@ -1711,8 +1726,15 @@ static const ut8 *parse_attr_value(const ut8 *obuf, int obuf_len,
 		value->kind = DW_AT_KIND_STRING;
 		value->string.offset = dwarf_read_offset (hdr->is_64bit, &buf, buf_end);
 		if (debug_str && value->string.offset < debug_str_len) {
-			const char *ds = (const char *)(debug_str + value->string.offset);
-			value->string.content = strdup (ds); // r_str_ndup (ds, debug_str_len - value->string.offset);
+			char *ds = r_str_ndup ((const char *)(debug_str + value->string.offset), debug_str_len);
+			if (ds) {
+				r_str_ansi_strip (ds);
+				r_str_replace_ch (ds, '\n', 0, true);
+				r_str_replace_ch (ds, '\t', 0, true);
+				value->string.content = ds;
+			} else {
+				value->string.content = NULL;
+			}
 		} else {
 			value->string.content = NULL; // Means malformed DWARF, should we print error message?
 		}
@@ -1903,8 +1925,11 @@ static const ut8 *parse_die(const ut8 *buf, const ut8 *buf_end, RBinDwarfAbbrevD
 		// Or atleast it needs to rework becase there will be
 		// more comp units -> more comp dirs and only the last one will be kept
 		if (attribute->attr_name == DW_AT_comp_dir && is_valid_string_form) {
-			const char *name = attribute->string.content;
-			sdb_set (sdb, "DW_AT_comp_dir", name, 0);
+			char *name = strdup (attribute->string.content);
+			r_str_ansi_strip (name);
+			r_str_replace_ch (name, '\n', 0, true);
+			r_str_replace_ch (name, '\t', 0, true);
+			sdb_set_owned (sdb, "DW_AT_comp_dir", name, 0);
 		}
 		die->count++;
 	}


avformat/nutdec: Add check for avformat_new_stream

Check for failure of avformat_new_stream() and propagate
the error code.

Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>

@@ -351,8 +351,12 @@ static int decode_main_header(NUTContext *nut)
         ret = AVERROR(ENOMEM);
         goto fail;
     }
-    for (i = 0; i < stream_count; i++)
-        avformat_new_stream(s, NULL);
+    for (i = 0; i < stream_count; i++) {
+        if (!avformat_new_stream(s, NULL)) {
+            ret = AVERROR(ENOMEM);
+            goto fail;
+        }
+    }

     return 0;
 fail:
@@ -800,19 +804,23 @@ static int nut_read_header(AVFormatContext *s)
     NUTContext *nut = s->priv_data;
     AVIOContext *bc = s->pb;
     int64_t pos;
-    int initialized_stream_count;
+    int initialized_stream_count, ret;

     nut->avf = s;

     /* main header */
     pos = 0;
+    ret = 0;
     do {
+        if (ret == AVERROR(ENOMEM))
+            return ret;
+
         pos = find_startcode(bc, MAIN_STARTCODE, pos) + 1;
         if (pos < 0 + 1) {
             av_log(s, AV_LOG_ERROR, "No main startcode found.\n");
             return AVERROR_INVALIDDATA;
         }
-    } while (decode_main_header(nut) < 0);
+    } while ((ret = decode_main_header(nut)) < 0);

     /* stream headers */
     pos = 0;


usb: dwc3: qcom: Fix NULL vs IS_ERR checking in dwc3_qcom_probe

Since the acpi_create_platform_device() function may return error
pointers, dwc3_qcom_create_urs_usb_platdev() function may return error
pointers too. Using IS_ERR_OR_NULL() to check the return value to fix this.

Fixes: c25c210f590e ("usb: dwc3: qcom: add URS Host support for sdm845 ACPI boot")
Signed-off-by: Miaoqian Lin <linmq006@gmail.com>
Link: https://lore.kernel.org/r/20211222111823.22887-1-linmq006@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

@@ -775,9 +775,12 @@ static int dwc3_qcom_probe(struct platform_device *pdev)

 		if (qcom->acpi_pdata->is_urs) {
 			qcom->urs_usb = dwc3_qcom_create_urs_usb_platdev(dev);
-			if (!qcom->urs_usb) {
+			if (IS_ERR_OR_NULL(qcom->urs_usb)) {
 				dev_err(dev, "failed to create URS USB platdev\n");
-				return -ENODEV;
+				if (!qcom->urs_usb)
+					return -ENODEV;
+				else
+					return PTR_ERR(qcom->urs_usb);
 			}
 		}
 	}


share: add sharing of HSTS cache among handles

Closes #10138

@@ -29,9 +29,11 @@
 #include "share.h"
 #include "psl.h"
 #include "vtls/vtls.h"
-#include "curl_memory.h"
+#include "hsts.h"

-/* The last #include file should be: */
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
 #include "memdebug.h"

 struct Curl_share *
@@ -89,6 +91,18 @@ curl_share_setopt(struct Curl_share *share, CURLSHoption option, ...)
 #endif
       break;

+    case CURL_LOCK_DATA_HSTS:
+#ifndef CURL_DISABLE_HSTS
+      if(!share->hsts) {
+        share->hsts = Curl_hsts_init();
+        if(!share->hsts)
+          res = CURLSHE_NOMEM;
+      }
+#else   /* CURL_DISABLE_HSTS */
+      res = CURLSHE_NOT_BUILT_IN;
+#endif
+      break;
+
     case CURL_LOCK_DATA_SSL_SESSION:
 #ifdef USE_SSL
       if(!share->sslsession) {
@@ -141,6 +155,16 @@ curl_share_setopt(struct Curl_share *share, CURLSHoption option, ...)
 #endif
       break;

+    case CURL_LOCK_DATA_HSTS:
+#ifndef CURL_DISABLE_HSTS
+      if(share->hsts) {
+        Curl_hsts_cleanup(&share->hsts);
+      }
+#else   /* CURL_DISABLE_HSTS */
+      res = CURLSHE_NOT_BUILT_IN;
+#endif
+      break;
+
     case CURL_LOCK_DATA_SSL_SESSION:
 #ifdef USE_SSL
       Curl_safefree(share->sslsession);
@@ -207,6 +231,10 @@ curl_share_cleanup(struct Curl_share *share)
   Curl_cookie_cleanup(share->cookies);
 #endif

+#ifndef CURL_DISABLE_HSTS
+  Curl_hsts_cleanup(&share->hsts);
+#endif
+
 #ifdef USE_SSL
   if(share->sslsession) {
     size_t i;


@@ -59,10 +59,14 @@ struct Curl_share {
 #ifdef USE_LIBPSL
   struct PslCache psl;
 #endif
-
+#ifndef CURL_DISABLE_HSTS
+  struct hsts *hsts;
+#endif
+#ifdef USE_SSL
   struct Curl_ssl_session *sslsession;
   size_t max_ssl_sessions;
   long sessionage;
+#endif
 };

 CURLSHcode Curl_share_lock(struct Curl_easy *, curl_lock_data,


Fix vi_pci_read null vc_cfgread function pointer dereference (GHSL-2021-054)

This is backport of what is done in bhyve

Signed-off-by: Frederic Dalleau <frederic.dalleau@docker.com>

@@ -559,7 +559,10 @@ vi_pci_read(UNUSED int vcpu, struct pci_devinst *pi, int baridx,
 		max = vc->vc_cfgsize ? vc->vc_cfgsize : 0x100000000;
 		if ((newoff + ((unsigned) size)) > max)
 			goto bad;
-		error = (*vc->vc_cfgread)(DEV_SOFTC(vs), ((int) newoff), size, &value);
+		if (vc->vc_cfgread != NULL)
+			error = (*vc->vc_cfgread)(DEV_SOFTC(vs), ((int) newoff), size, &value);
+		else
+			error = 0;
 		if (!error)
 			goto done;
 	}


@@ -61,6 +61,11 @@
  *   not the symlinks themselves, which is the default behavior. Broken
  *   symlinks are ignored.
  *
+ *   Note: setting DIR_ITERATOR_FOLLOW_SYMLINKS affects resolving the
+ *   starting path as well (e.g., attempting to iterate starting at a
+ *   symbolic link pointing to a directory without FOLLOW_SYMLINKS will
+ *   result in an error).
+ *
  * Warning: circular symlinks are also followed when
  * DIR_ITERATOR_FOLLOW_SYMLINKS is set. The iteration may end up with
  * an ELOOP if they happen and DIR_ITERATOR_PEDANTIC is set.


sgpd box entry: disallow null grouping_type (#2389)

@@ -4429,7 +4429,7 @@ GF_Err video_sample_entry_box_size(GF_Box *s)

 	/*VVC*/
 	gf_isom_check_position(s, (GF_Box *)ptr->vvc_config, &pos);
-
+
 	/*AV1*/
 	gf_isom_check_position(s, (GF_Box *)ptr->av1_config, &pos);

@@ -8857,7 +8857,7 @@ GF_Err dac3_box_write(GF_Box *s, GF_BitStream *bs)
 	e = gf_isom_box_write_header(s, bs);
 	if (ptr->cfg.is_ec3) s->type = GF_ISOM_BOX_TYPE_DAC3;
 	if (e) return e;
-
+
 	e = gf_odf_ac3_cfg_write_bs(&ptr->cfg, bs);
 	if (e) return e;

@@ -9983,6 +9983,9 @@ static void *sgpd_parse_entry(u32 grouping_type, GF_BitStream *bs, s32 bytes_in_
 		}
 		return ptr;
 	}
+	case 0:
+		GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] sgpd entry null grouping_type is invalid\n") );
+		return NULL;
 	default:
 		break;
 	}


certmap: sanitize LDAP search filter

The sss_certmap_get_search_filter() will now sanitize the values read
from the certificates before adding them to a search filter. To be able
to get the plain values as well sss_certmap_expand_mapping_rule() is
added.

Resolves:
https://github.com/SSSD/sssd/issues/5135

Reviewed-by: Alexey Tikhonov <atikhono@redhat.com>

@@ -441,10 +441,12 @@ static int expand_san(struct sss_certmap_ctx *ctx,
 static int expand_template(struct sss_certmap_ctx *ctx,
                            struct parsed_template *parsed_template,
                            struct sss_cert_content *cert_content,
+                           bool sanitize,
                            char **expanded)
 {
     int ret;
     char *exp = NULL;
+    char *exp_sanitized = NULL;

     if (strcmp("issuer_dn", parsed_template->name) == 0) {
         ret = rdn_list_2_dn_str(ctx, parsed_template->conversion,
@@ -455,6 +457,8 @@ static int expand_template(struct sss_certmap_ctx *ctx,
     } else if (strncmp("subject_", parsed_template->name, 8) == 0) {
         ret = expand_san(ctx, parsed_template, cert_content->san_list, &exp);
     } else if (strcmp("cert", parsed_template->name) == 0) {
+        /* cert blob is already sanitized */
+        sanitize = false;
         ret = expand_cert(ctx, parsed_template, cert_content, &exp);
     } else {
         CM_DEBUG(ctx, "Unsupported template name.");
@@ -471,6 +475,16 @@ static int expand_template(struct sss_certmap_ctx *ctx,
         goto done;
     }

+    if (sanitize) {
+        ret = sss_filter_sanitize(ctx, exp, &exp_sanitized);
+        if (ret != EOK) {
+            CM_DEBUG(ctx, "Failed to sanitize expanded template.");
+            goto done;
+        }
+        talloc_free(exp);
+        exp = exp_sanitized;
+    }
+
     ret = 0;

 done:
@@ -485,7 +499,7 @@ static int expand_template(struct sss_certmap_ctx *ctx,

 static int get_filter(struct sss_certmap_ctx *ctx,
                       struct ldap_mapping_rule *parsed_mapping_rule,
-                      struct sss_cert_content *cert_content,
+                      struct sss_cert_content *cert_content, bool sanitize,
                       char **filter)
 {
     struct ldap_mapping_rule_comp *comp;
@@ -503,7 +517,7 @@ static int get_filter(struct sss_certmap_ctx *ctx,
             result = talloc_strdup_append(result, comp->val);
         } else if (comp->type == comp_template) {
             ret = expand_template(ctx, comp->parsed_template, cert_content,
-                                  &expanded);
+                                  sanitize, &expanded);
             if (ret != 0) {
                 CM_DEBUG(ctx, "Failed to expanded template.");
                 goto done;
@@ -791,8 +805,9 @@ int sss_certmap_match_cert(struct sss_certmap_ctx *ctx,
     return ret;
 }

-int sss_certmap_get_search_filter(struct sss_certmap_ctx *ctx,
+static int expand_mapping_rule_ex(struct sss_certmap_ctx *ctx,
                                   const uint8_t *der_cert, size_t der_size,
+                                  bool sanitize,
                                   char **_filter, char ***_domains)
 {
     int ret;
@@ -819,7 +834,8 @@ int sss_certmap_get_search_filter(struct sss_certmap_ctx *ctx,
             return EINVAL;
         }

-        ret = get_filter(ctx, ctx->default_mapping_rule, cert_content, &filter);
+        ret = get_filter(ctx, ctx->default_mapping_rule, cert_content, sanitize,
+                         &filter);
         goto done;
     }

@@ -829,7 +845,7 @@ int sss_certmap_get_search_filter(struct sss_certmap_ctx *ctx,
             if (ret == 0) {
                 /* match */
                 ret = get_filter(ctx, r->parsed_mapping_rule, cert_content,
-                                 &filter);
+                                 sanitize, &filter);
                 if (ret != 0) {
                     CM_DEBUG(ctx, "Failed to get filter");
                     goto done;
@@ -873,6 +889,22 @@ int sss_certmap_get_search_filter(struct sss_certmap_ctx *ctx,
     return ret;
 }

+int sss_certmap_get_search_filter(struct sss_certmap_ctx *ctx,
+                                  const uint8_t *der_cert, size_t der_size,
+                                  char **_filter, char ***_domains)
+{
+    return expand_mapping_rule_ex(ctx, der_cert, der_size, true,
+                                  _filter, _domains);
+}
+
+int sss_certmap_expand_mapping_rule(struct sss_certmap_ctx *ctx,
+                                    const uint8_t *der_cert, size_t der_size,
+                                    char **_expanded, char ***_domains)
+{
+    return expand_mapping_rule_ex(ctx, der_cert, der_size, false,
+                                  _expanded, _domains);
+}
+
 int sss_certmap_init(TALLOC_CTX *mem_ctx,
                      sss_certmap_ext_debug *debug, void *debug_priv,
                      struct sss_certmap_ctx **ctx)


@@ -2953,6 +2953,7 @@ typedef enum {
   CURL_LOCK_DATA_SSL_SESSION,
   CURL_LOCK_DATA_CONNECT,
   CURL_LOCK_DATA_PSL,
+  CURL_LOCK_DATA_HSTS,
   CURL_LOCK_DATA_LAST
 } curl_lock_data;


url: only reuse connections with same GSS delegation

Reported-by: Harry Sintonen
Closes #10731

@@ -1061,6 +1061,7 @@ struct connectdata {
   unsigned char ip_version; /* copied from the Curl_easy at creation time */
   unsigned char httpversion; /* the HTTP version*10 reported by the server */
   unsigned char connect_only;
+  unsigned char gssapi_delegation; /* inherited from set.gssapi_delegation */
 };

 /* The end of connectdata. */


@@ -23,15 +23,15 @@
 #include <atalk/util.h>
 #include <atalk/logger.h>

-size_t dsi_writeinit(DSI *dsi, void *buf, const size_t buflen _U_)
+size_t dsi_writeinit(DSI *dsi, void *buf, const size_t buflen)
 {
     size_t bytes = 0;
     dsi->datasize = ntohl(dsi->header.dsi_len) - dsi->header.dsi_data.dsi_doff;

     if (dsi->eof > dsi->start) {
         /* We have data in the buffer */
         bytes = MIN(dsi->eof - dsi->start, dsi->datasize);
-        memmove(buf, dsi->start, bytes);
+        memmove(buf, dsi->start, MIN(buflen, bytes));
         dsi->start += bytes;
         dsi->datasize -= bytes;
         if (dsi->start >= dsi->eof)


Avoid assertion when MSETNX is used with the same key twice (CVE-2023-28425) (#11940)

Using the same key twice in MSETNX command would trigger an assertion.

This reverts #11594 (introduced in Redis 7.0.8)

@@ -559,7 +559,6 @@ void mgetCommand(client *c) {

 void msetGenericCommand(client *c, int nx) {
     int j;
-    int setkey_flags = 0;

     if ((c->argc % 2) == 0) {
         addReplyErrorArity(c);
@@ -575,12 +574,11 @@ void msetGenericCommand(client *c, int nx) {
                 return;
             }
         }
-        setkey_flags |= SETKEY_DOESNT_EXIST;
     }

     for (j = 1; j < c->argc; j += 2) {
         c->argv[j+1] = tryObjectEncoding(c->argv[j+1]);
-        setKey(c, c->db, c->argv[j], c->argv[j + 1], setkey_flags);
+        setKey(c, c->db, c->argv[j], c->argv[j + 1], 0);
         notifyKeyspaceEvent(NOTIFY_STRING,"set",c->argv[j],c->db->id);
     }
     server.dirty += (c->argc-1)/2;


Reject paths given to --filesystem/--persist with special characters

There isn't much in the way of legit reasons for this, but it's a
potential security footgun when displaying the text.

CVE-2023-28101, GHSA-h43h-fwqx-mpp8

Signed-off-by: Ryan Gonzalez <ryan.gonzalez@collabora.com>
Co-authored-by: Simon McVittie <smcv@collabora.com>

@@ -937,6 +937,9 @@ char * flatpak_escape_string (const char        *s,
 void   flatpak_print_escaped_string (const char        *s,
                                      FlatpakEscapeFlags flags);

+gboolean flatpak_validate_path_characters (const char *path,
+                                           GError    **error);
+
 gboolean running_under_sudo (void);

 #define FLATPAK_MESSAGE_ID "c7b39b1e006b464599465e105b361485"


Escape control characters in log messages and "sudoreplay -l" output.
The log message contains user-controlled strings that could include
things like terminal control characters.  Space characters in the
command path are now also escaped.

Command line arguments that contain spaces are surrounded with
single quotes and any literal single quote or backslash characters
are escaped with a backslash.  This makes it possible to distinguish
multiple command line arguments from a single argument that contains
spaces.

Issue found by Matthieu Barjole and Victor Cutillas of Synacktiv
(https://synacktiv.com).

@@ -62,6 +62,7 @@
 #include "sudo_debug.h"
 #include "sudo_event.h"
 #include "sudo_eventlog.h"
+#include "sudo_lbuf.h"
 #include "sudo_fatal.h"
 #include "sudo_gettext.h"
 #include "sudo_iolog.h"
@@ -373,6 +374,10 @@ main(int argc, char *argv[])
     if ((evlog = iolog_parse_loginfo(iolog_dir_fd, iolog_dir)) == NULL)
 	goto done;
     printf(_("Replaying sudo session: %s"), evlog->command);
+    if (evlog->argv != NULL && evlog->argv[0] != NULL) {
+	for (i = 1; evlog->argv[i] != NULL; i++)
+	    printf(" %s", evlog->argv[i]);
+    }

     /* Setup terminal if appropriate. */
     if (!isatty(STDIN_FILENO) || !isatty(STDOUT_FILENO))
@@ -1315,11 +1320,57 @@ parse_expr(struct search_node_list *head, char *argv[], bool sub_expr)
     debug_return_int(av - argv);
 }

+static char *
+expand_command(struct eventlog *evlog, char **newbuf)
+{
+    size_t len, bufsize = strlen(evlog->command) + 1;
+    char *cp, *buf;
+    int ac;
+    debug_decl(expand_command, SUDO_DEBUG_UTIL);
+
+    if (evlog->argv == NULL || evlog->argv[0] == NULL || evlog->argv[1] == NULL) {
+	/* No arguments, we can use the command as-is. */
+	*newbuf = NULL;
+	debug_return_str(evlog->command);
+    }
+
+    /* Skip argv[0], we use evlog->command instead. */
+    for (ac = 1; evlog->argv[ac] != NULL; ac++)
+	bufsize += strlen(evlog->argv[ac]) + 1;
+
+    if ((buf = malloc(bufsize)) == NULL)
+	sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
+    cp = buf;
+
+    len = strlcpy(cp, evlog->command, bufsize);
+    if (len >= bufsize)
+	sudo_fatalx(U_("internal error, %s overflow"), __func__);
+    cp += len;
+    bufsize -= len;
+
+    for (ac = 1; evlog->argv[ac] != NULL; ac++) {
+	if (bufsize < 2)
+	    sudo_fatalx(U_("internal error, %s overflow"), __func__);
+	*cp++ = ' ';
+	bufsize--;
+
+	len = strlcpy(cp, evlog->argv[ac], bufsize);
+	if (len >= bufsize)
+	    sudo_fatalx(U_("internal error, %s overflow"), __func__);
+	cp += len;
+	bufsize -= len;
+    }
+
+    *newbuf = buf;
+    debug_return_str(buf);
+}
+
 static bool
 match_expr(struct search_node_list *head, struct eventlog *evlog, bool last_match)
 {
     struct search_node *sn;
     bool res = false, matched = last_match;
+    char *tofree;
     int rc;
     debug_decl(match_expr, SUDO_DEBUG_UTIL);

@@ -1353,13 +1404,15 @@ match_expr(struct search_node_list *head, struct eventlog *evlog, bool last_matc
 		res = strcmp(sn->u.user, evlog->submituser) == 0;
 	    break;
 	case ST_PATTERN:
-	    rc = regexec(&sn->u.cmdre, evlog->command, 0, NULL, 0);
+	    rc = regexec(&sn->u.cmdre, expand_command(evlog, &tofree),
+		0, NULL, 0);
 	    if (rc && rc != REG_NOMATCH) {
 		char buf[BUFSIZ];
 		regerror(rc, &sn->u.cmdre, buf, sizeof(buf));
 		sudo_fatalx("%s", buf);
 	    }
 	    res = rc == REG_NOMATCH ? 0 : 1;
+	    free(tofree);
 	    break;
 	case ST_FROMDATE:
 	    res = sudo_timespeccmp(&evlog->submit_time, &sn->u.tstamp, >=);
@@ -1380,12 +1433,13 @@ match_expr(struct search_node_list *head, struct eventlog *evlog, bool last_matc
 }

 static int
-list_session(char *log_dir, regex_t *re, const char *user, const char *tty)
+list_session(struct sudo_lbuf *lbuf, char *log_dir, regex_t *re,
+    const char *user, const char *tty)
 {
     char idbuf[7], *idstr, *cp;
     struct eventlog *evlog = NULL;
     const char *timestr;
-    int ret = -1;
+    int i, ret = -1;
     debug_decl(list_session, SUDO_DEBUG_UTIL);

     if ((evlog = iolog_parse_loginfo(-1, log_dir)) == NULL)
@@ -1417,23 +1471,71 @@ list_session(char *log_dir, regex_t *re, const char *user, const char *tty)
     }
     /* XXX - print lines + cols? */
     timestr = get_timestr(evlog->submit_time.tv_sec, 1);
-    printf("%s : %s : ", timestr ? timestr : "invalid date", evlog->submituser);
-    if (evlog->submithost != NULL)
-	printf("HOST=%s ; ", evlog->submithost);
-    if (evlog->ttyname != NULL)
-	printf("TTY=%s ; ", evlog->ttyname);
-    if (evlog->runchroot != NULL)
-	printf("CHROOT=%s ; ", evlog->runchroot);
-    if (evlog->runcwd != NULL || evlog->cwd != NULL)
-	printf("CWD=%s ; ", evlog->runcwd ? evlog->runcwd : evlog->cwd);
-    printf("USER=%s ; ", evlog->runuser);
-    if (evlog->rungroup != NULL)
-	printf("GROUP=%s ; ", evlog->rungroup);
-    printf("TSID=%s ; COMMAND=%s\n", idstr, evlog->command);
-
-    ret = 0;
+    sudo_lbuf_append_esc(lbuf, LBUF_ESC_CNTRL, "%s : %s : ",
+	timestr ? timestr : "invalid date", evlog->submituser);
+    if (evlog->submithost != NULL) {
+	sudo_lbuf_append_esc(lbuf, LBUF_ESC_CNTRL, "HOST=%s ; ",
+	    evlog->submithost);
+    }
+    if (evlog->ttyname != NULL) {
+	sudo_lbuf_append_esc(lbuf, LBUF_ESC_CNTRL, "TTY=%s ; ",
+	    evlog->ttyname);
+    }
+    if (evlog->runchroot != NULL) {
+	sudo_lbuf_append_esc(lbuf, LBUF_ESC_CNTRL, "CHROOT=%s ; ",
+	    evlog->runchroot);
+    }
+    if (evlog->runcwd != NULL || evlog->cwd != NULL) {
+	sudo_lbuf_append_esc(lbuf, LBUF_ESC_CNTRL, "CWD=%s ; ",
+	    evlog->runcwd ? evlog->runcwd : evlog->cwd);
+    }
+    sudo_lbuf_append_esc(lbuf, LBUF_ESC_CNTRL, "USER=%s ; ", evlog->runuser);
+    if (evlog->rungroup != NULL) {
+	sudo_lbuf_append_esc(lbuf, LBUF_ESC_CNTRL, "GROUP=%s ; ",
+	    evlog->rungroup);
+    }
+    sudo_lbuf_append_esc(lbuf, LBUF_ESC_CNTRL, "TSID=%s ; ", idstr);
+
+    /*
+     * If we have both command and argv from info.json we can escape
+     * blanks in the the command and arguments.  If all we have is a
+     * single string containing both the command and arguments we cannot.
+     */
+    if (evlog->argv != NULL) {
+	/* Command plus argv from the info.json file. */
+	sudo_lbuf_append_esc(lbuf, LBUF_ESC_CNTRL|LBUF_ESC_BLANK,
+	    "COMMAND=%s", evlog->command);
+	if (evlog->argv[0] != NULL) {
+	    for (i = 1; evlog->argv[i] != NULL; i++) {
+		sudo_lbuf_append(lbuf, " ");
+		if (strchr(evlog->argv[i], ' ') != NULL) {
+		    /* Wrap args containing spaces in single quotes. */
+		    sudo_lbuf_append(lbuf, "'");
+		    sudo_lbuf_append_esc(lbuf, LBUF_ESC_CNTRL|LBUF_ESC_QUOTE,
+			"%s", evlog->argv[i]);
+		    sudo_lbuf_append(lbuf, "'");
+		} else {
+		    /* Escape quotes here too for consistency. */
+		    sudo_lbuf_append_esc(lbuf,
+			LBUF_ESC_CNTRL|LBUF_ESC_BLANK|LBUF_ESC_QUOTE,
+			"%s", evlog->argv[i]);
+		}
+	    }
+	}
+    } else {
+	/* Single string from the legacy info file. */
+	sudo_lbuf_append_esc(lbuf, LBUF_ESC_CNTRL, "COMMAND=%s",
+	    evlog->command);
+    }
+
+    if (!sudo_lbuf_error(lbuf)) {
+	puts(lbuf->buf);
+	ret = 0;
+    }

 done:
+    lbuf->error = 0;
+    lbuf->len = 0;
     eventlog_free(evlog);
     debug_return_int(ret);
 }
@@ -1453,6 +1555,7 @@ find_sessions(const char *dir, regex_t *re, const char *user, const char *tty)
     DIR *d;
     struct dirent *dp;
     struct stat sb;
+    struct sudo_lbuf lbuf;
     size_t sdlen, sessions_len = 0, sessions_size = 0;
     unsigned int i;
     int len;
@@ -1464,6 +1567,8 @@ find_sessions(const char *dir, regex_t *re, const char *user, const char *tty)
 #endif
     debug_decl(find_sessions, SUDO_DEBUG_UTIL);

+    sudo_lbuf_init(&lbuf, NULL, 0, NULL, 0);
+
     d = opendir(dir);
     if (d == NULL)
 	sudo_fatal(U_("unable to open %s"), dir);
@@ -1524,7 +1629,7 @@ find_sessions(const char *dir, regex_t *re, const char *user, const char *tty)
 	    /* Check for dir with a log file. */
 	    if (lstat(pathbuf, &sb) == 0 && S_ISREG(sb.st_mode)) {
 		pathbuf[sdlen + len - 4] = '\0';
-		list_session(pathbuf, re, user, tty);
+		list_session(&lbuf, pathbuf, re, user, tty);
 	    } else {
 		/* Strip off "/log" and recurse if a non-log dir. */
 		pathbuf[sdlen + len - 4] = '\0';
@@ -1535,6 +1640,7 @@ find_sessions(const char *dir, regex_t *re, const char *user, const char *tty)
 	}
 	free(sessions);
     }
+    sudo_lbuf_destroy(&lbuf);

     debug_return_int(0);
 }


[sipmsgops] fix codec_delete_XX() parsing (2)

Issue discovered during OpenSIPS Security Audit 2021,
	by Alfred Farrugia & Sandro Gauci (Enable Security)

https://github.com/OpenSIPS/opensips/security/advisories/GHSA-67w7-g4j8-3wcx

@@ -366,7 +366,8 @@ int delete_sdp_line( struct sip_msg * msg, char * s, struct sdp_stream_cell *str

 	while(*end != '\n' && end < (stream->body.s+stream->body.len) )
 		end++;
-	end++;
+	if ( *end == '\n')
+		end++;

 	/* delete the entry */
 	if( del_lump(msg, start - msg->buf, end - start,0) == NULL )


Fix conversion from GDB register profile to rizin profile

@@ -214,4 +214,7 @@ typedef struct _utX {
 		return m ? *m = n, m : m; \
 	}

+#define RZ_STR_DEF(s) RZ_STR(s)
+#define RZ_STR(s)     #s
+
 #endif // RZ_TYPES_BASE_H


Binding the accept socket in TCP input relies on the fact that the
listen port is not bound to port 0.  With a matching pf divert-to
rule this assumption is no longer true and could crash the kernel
with kassert.  In both pf and stack drop TCP packets with destination
port 0 before they can do harm.
OK sashan@ claudio@

@@ -1,4 +1,4 @@
-/*	$OpenBSD: pf.c,v 1.1169 2023/01/06 17:44:34 sashan Exp $ */
+/*	$OpenBSD: pf.c,v 1.1170 2023/01/12 13:09:47 bluhm Exp $ */

 /*
  * Copyright (c) 2001 Daniel Hartmeier
@@ -7254,7 +7254,8 @@ pf_setup_pdesc(struct pf_pdesc *pd, sa_family_t af, int dir,
 		    NULL, reason, pd->af))
 			return (PF_DROP);
 		pd->hdrlen = sizeof(*th);
-		if (pd->off + (th->th_off << 2) > pd->tot_len ||
+		if (th->th_dport == 0 ||
+		    pd->off + (th->th_off << 2) > pd->tot_len ||
 		    (th->th_off << 2) < sizeof(struct tcphdr)) {
 			REASON_SET(reason, PFRES_SHORT);
 			return (PF_DROP);


Bluetooth: hci_qca: Fix NULL vs IS_ERR_OR_NULL check in qca_serdev_probe

The function devm_gpiod_get_index() return error pointers on error.
Thus devm_gpiod_get_index_optional() could return NULL and error pointers.
The same as devm_gpiod_get_optional() function. Using IS_ERR_OR_NULL()
check to catch error pointers.

Fixes: 77131dfe ("Bluetooth: hci_qca: Replace devm_gpiod_get() with devm_gpiod_get_optional()")
Signed-off-by: Miaoqian Lin <linmq006@gmail.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>

@@ -2059,14 +2059,14 @@ static int qca_serdev_probe(struct serdev_device *serdev)

 		qcadev->bt_en = devm_gpiod_get_optional(&serdev->dev, "enable",
 					       GPIOD_OUT_LOW);
-		if (!qcadev->bt_en && data->soc_type == QCA_WCN6750) {
+		if (IS_ERR_OR_NULL(qcadev->bt_en) && data->soc_type == QCA_WCN6750) {
 			dev_err(&serdev->dev, "failed to acquire BT_EN gpio\n");
 			power_ctrl_enabled = false;
 		}

 		qcadev->sw_ctrl = devm_gpiod_get_optional(&serdev->dev, "swctrl",
 					       GPIOD_IN);
-		if (!qcadev->sw_ctrl && data->soc_type == QCA_WCN6750)
+		if (IS_ERR_OR_NULL(qcadev->sw_ctrl) && data->soc_type == QCA_WCN6750)
 			dev_warn(&serdev->dev, "failed to acquire SW_CTRL gpio\n");

 		qcadev->susclk = devm_clk_get_optional(&serdev->dev, NULL);
@@ -2088,7 +2088,7 @@ static int qca_serdev_probe(struct serdev_device *serdev)

 		qcadev->bt_en = devm_gpiod_get_optional(&serdev->dev, "enable",
 					       GPIOD_OUT_LOW);
-		if (!qcadev->bt_en) {
+		if (IS_ERR_OR_NULL(qcadev->bt_en)) {
 			dev_warn(&serdev->dev, "failed to acquire enable gpio\n");
 			power_ctrl_enabled = false;
 		}


net: sched: sch_qfq: prevent slab-out-of-bounds in qfq_activate_agg

If the TCA_QFQ_LMAX value is not offered through nlattr, lmax is determined by the MTU value of the network device.
The MTU of the loopback device can be set up to 2^31-1.
As a result, it is possible to have an lmax value that exceeds QFQ_MIN_LMAX.

Due to the invalid lmax value, an index is generated that exceeds the QFQ_MAX_INDEX(=24) value, causing out-of-bounds read/write errors.

The following reports a oob access:

[   84.582666] BUG: KASAN: slab-out-of-bounds in qfq_activate_agg.constprop.0 (net/sched/sch_qfq.c:1027 net/sched/sch_qfq.c:1060 net/sched/sch_qfq.c:1313)
[   84.583267] Read of size 4 at addr ffff88810f676948 by task ping/301
[   84.583686]
[   84.583797] CPU: 3 PID: 301 Comm: ping Not tainted 6.3.0-rc5 #1
[   84.584164] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.15.0-1 04/01/2014
[   84.584644] Call Trace:
[   84.584787]  <TASK>
[   84.584906] dump_stack_lvl (lib/dump_stack.c:107 (discriminator 1))
[   84.585108] print_report (mm/kasan/report.c:320 mm/kasan/report.c:430)
[   84.585570] kasan_report (mm/kasan/report.c:538)
[   84.585988] qfq_activate_agg.constprop.0 (net/sched/sch_qfq.c:1027 net/sched/sch_qfq.c:1060 net/sched/sch_qfq.c:1313)
[   84.586599] qfq_enqueue (net/sched/sch_qfq.c:1255)
[   84.587607] dev_qdisc_enqueue (net/core/dev.c:3776)
[   84.587749] __dev_queue_xmit (./include/net/sch_generic.h:186 net/core/dev.c:3865 net/core/dev.c:4212)
[   84.588763] ip_finish_output2 (./include/net/neighbour.h:546 net/ipv4/ip_output.c:228)
[   84.589460] ip_output (net/ipv4/ip_output.c:430)
[   84.590132] ip_push_pending_frames (./include/net/dst.h:444 net/ipv4/ip_output.c:126 net/ipv4/ip_output.c:1586 net/ipv4/ip_output.c:1606)
[   84.590285] raw_sendmsg (net/ipv4/raw.c:649)
[   84.591960] sock_sendmsg (net/socket.c:724 net/socket.c:747)
[   84.592084] __sys_sendto (net/socket.c:2142)
[   84.593306] __x64_sys_sendto (net/socket.c:2150)
[   84.593779] do_syscall_64 (arch/x86/entry/common.c:50 arch/x86/entry/common.c:80)
[   84.593902] entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:120)
[   84.594070] RIP: 0033:0x7fe568032066
[   84.594192] Code: 0e 0d 00 f7 d8 64 89 02 48 c7 c0 ff ff ff ff eb b8 0f 1f 00 41 89 ca 64 8b 04 25 18 00 00 00 85 c09[ 84.594796] RSP: 002b:00007ffce388b4e8 EFLAGS: 00000246 ORIG_RAX: 000000000000002c

Code starting with the faulting instruction
===========================================
[   84.595047] RAX: ffffffffffffffda RBX: 00007ffce388cc70 RCX: 00007fe568032066
[   84.595281] RDX: 0000000000000040 RSI: 00005605fdad6d10 RDI: 0000000000000003
[   84.595515] RBP: 00005605fdad6d10 R08: 00007ffce388eeec R09: 0000000000000010
[   84.595749] R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000040
[   84.595984] R13: 00007ffce388cc30 R14: 00007ffce388b4f0 R15: 0000001d00000001
[   84.596218]  </TASK>
[   84.596295]
[   84.596351] Allocated by task 291:
[   84.596467] kasan_save_stack (mm/kasan/common.c:46)
[   84.596597] kasan_set_track (mm/kasan/common.c:52)
[   84.596725] __kasan_kmalloc (mm/kasan/common.c:384)
[   84.596852] __kmalloc_node (./include/linux/kasan.h:196 mm/slab_common.c:967 mm/slab_common.c:974)
[   84.596979] qdisc_alloc (./include/linux/slab.h:610 ./include/linux/slab.h:731 net/sched/sch_generic.c:938)
[   84.597100] qdisc_create (net/sched/sch_api.c:1244)
[   84.597222] tc_modify_qdisc (net/sched/sch_api.c:1680)
[   84.597357] rtnetlink_rcv_msg (net/core/rtnetlink.c:6174)
[   84.597495] netlink_rcv_skb (net/netlink/af_netlink.c:2574)
[   84.597627] netlink_unicast (net/netlink/af_netlink.c:1340 net/netlink/af_netlink.c:1365)
[   84.597759] netlink_sendmsg (net/netlink/af_netlink.c:1942)
[   84.597891] sock_sendmsg (net/socket.c:724 net/socket.c:747)
[   84.598016] ____sys_sendmsg (net/socket.c:2501)
[   84.598147] ___sys_sendmsg (net/socket.c:2557)
[   84.598275] __sys_sendmsg (./include/linux/file.h:31 net/socket.c:2586)
[   84.598399] do_syscall_64 (arch/x86/entry/common.c:50 arch/x86/entry/common.c:80)
[   84.598520] entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:120)
[   84.598688]
[   84.598744] The buggy address belongs to the object at ffff88810f674000
[   84.598744]  which belongs to the cache kmalloc-8k of size 8192
[   84.599135] The buggy address is located 2664 bytes to the right of
[   84.599135]  allocated 7904-byte region [ffff88810f674000, ffff88810f675ee0)
[   84.599544]
[   84.599598] The buggy address belongs to the physical page:
[   84.599777] page:00000000e638567f refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x10f670
[   84.600074] head:00000000e638567f order:3 entire_mapcount:0 nr_pages_mapped:0 pincount:0
[   84.600330] flags: 0x200000000010200(slab|head|node=0|zone=2)
[   84.600517] raw: 0200000000010200 ffff888100043180 dead000000000122 0000000000000000
[   84.600764] raw: 0000000000000000 0000000080020002 00000001ffffffff 0000000000000000
[   84.601009] page dumped because: kasan: bad access detected
[   84.601187]
[   84.601241] Memory state around the buggy address:
[   84.601396]  ffff88810f676800: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
[   84.601620]  ffff88810f676880: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
[   84.601845] >ffff88810f676900: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
[   84.602069]                                               ^
[   84.602243]  ffff88810f676980: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
[   84.602468]  ffff88810f676a00: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
[   84.602693] ==================================================================
[   84.602924] Disabling lock debugging due to kernel taint

Fixes: 3015f3d2a3cd ("pkt_sched: enable QFQ to support TSO/GSO")
Reported-by: Gwangun Jung <exsociety@gmail.com>
Signed-off-by: Gwangun Jung <exsociety@gmail.com>
Acked-by: Jamal Hadi Salim<jhs@mojatatu.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

@@ -421,15 +421,16 @@ static int qfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
 	} else
 		weight = 1;

-	if (tb[TCA_QFQ_LMAX]) {
+	if (tb[TCA_QFQ_LMAX])
 		lmax = nla_get_u32(tb[TCA_QFQ_LMAX]);
-		if (lmax < QFQ_MIN_LMAX || lmax > (1UL << QFQ_MTU_SHIFT)) {
-			pr_notice("qfq: invalid max length %u\n", lmax);
-			return -EINVAL;
-		}
-	} else
+	else
 		lmax = psched_mtu(qdisc_dev(sch));

+	if (lmax < QFQ_MIN_LMAX || lmax > (1UL << QFQ_MTU_SHIFT)) {
+		pr_notice("qfq: invalid max length %u\n", lmax);
+		return -EINVAL;
+	}
+
 	inv_w = ONE_FP / weight;
 	weight = ONE_FP / inv_w;


fix hincrbyfloat not to create a key if the new value is invalid (#11149)

Check the validity of the value before performing the create operation,
prevents new data from being generated even if the request fails to execute.

Co-authored-by: Oran Agra <oran@redislabs.com>
Co-authored-by: chendianqiang <chendianqiang@meituan.com>
Co-authored-by: Binbin <binloveplay1314@qq.com>

@@ -666,6 +666,10 @@ void hincrbyfloatCommand(client *c) {
     unsigned int vlen;

     if (getLongDoubleFromObjectOrReply(c,c->argv[3],&incr,NULL) != C_OK) return;
+    if (isnan(incr) || isinf(incr)) {
+        addReplyError(c,"value is NaN or Infinity");
+        return;
+    }
     if ((o = hashTypeLookupWriteOrCreate(c,c->argv[1])) == NULL) return;
     if (hashTypeGetValue(o,c->argv[2]->ptr,&vstr,&vlen,&ll) == C_OK) {
         if (vstr) {


ADDED: Security check for `emscripten_run_script()` #2954

@@ -1994,7 +1994,9 @@ void SetClipboardText(const char *text)
     glfwSetClipboardString(CORE.Window.handle, text);
 #endif
 #if defined(PLATFORM_WEB)
-    emscripten_run_script(TextFormat("navigator.clipboard.writeText('%s')", text));
+    // Security check to (partially) avoid malicious code
+    if (strchr(text, '\'') != NULL) TRACELOG(LOG_WARNING, "SYSTEM: Provided Clipboard could be potentially malicious, avoid [\'] character");
+    else emscripten_run_script(TextFormat("navigator.clipboard.writeText('%s')", text));
 #endif
 }

@@ -2006,6 +2008,7 @@ const char *GetClipboardText(void)
     return glfwGetClipboardString(CORE.Window.handle);
 #endif
 #if defined(PLATFORM_WEB)
+/*
     // Accessing clipboard data from browser is tricky due to security reasons
     // The method to use is navigator.clipboard.readText() but this is an asynchronous method
     // that will return at some moment after the function is called with the required data
@@ -2019,7 +2022,7 @@ const char *GetClipboardText(void)

     // Another approach could be just copy the data in a HTML text field and try to retrieve it
     // later on if available... and clean it for future accesses
-
+*/
     return NULL;
 #endif
     return NULL;
@@ -2910,6 +2913,9 @@ void SetConfigFlags(unsigned int flags)
 void TakeScreenshot(const char *fileName)
 {
 #if defined(SUPPORT_MODULE_RTEXTURES)
+    // Security check to (partially) avoid malicious code on PLATFORM_WEB
+    if (strchr(fileName, '\'') != NULL) { TRACELOG(LOG_WARNING, "SYSTEM: Provided fileName could be potentially malicious, avoid [\'] character");  return; }
+
     Vector2 scale = GetWindowScaleDPI();
     unsigned char *imgData = rlReadScreenPixels((int)((float)CORE.Window.render.width*scale.x), (int)((float)CORE.Window.render.height*scale.y));
     Image image = { imgData, (int)((float)CORE.Window.render.width*scale.x), (int)((float)CORE.Window.render.height*scale.y), 1, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 };
@@ -3536,12 +3542,8 @@ unsigned char *DecodeDataBase64(const unsigned char *data, int *outputSize)
 // Ref: https://github.com/raysan5/raylib/issues/686
 void OpenURL(const char *url)
 {
-    // Small security check trying to avoid (partially) malicious code...
-    // sorry for the inconvenience when you hit this point...
-    if (strchr(url, '\'') != NULL)
-    {
-        TRACELOG(LOG_WARNING, "SYSTEM: Provided URL is not valid");
-    }
+    // Security check to (aprtially) avoid malicious code on PLATFORM_WEB
+    if (strchr(url, '\'') != NULL) TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'] character");
     else
     {
 #if defined(PLATFORM_DESKTOP)


KVM: nVMX: add missing consistency checks for CR0 and CR4

The effective values of the guest CR0 and CR4 registers may differ from
those included in the VMCS12.  In particular, disabling EPT forces
CR4.PAE=1 and disabling unrestricted guest mode forces CR0.PG=CR0.PE=1.

Therefore, checks on these bits cannot be delegated to the processor
and must be performed by KVM.

Reported-by: Reima ISHII <ishiir@g.ecc.u-tokyo.ac.jp>
Cc: stable@vger.kernel.org
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

@@ -3022,7 +3022,7 @@ static int nested_vmx_check_guest_state(struct kvm_vcpu *vcpu,
 					struct vmcs12 *vmcs12,
 					enum vm_entry_failure_code *entry_failure_code)
 {
-	bool ia32e;
+	bool ia32e = !!(vmcs12->vm_entry_controls & VM_ENTRY_IA32E_MODE);

 	*entry_failure_code = ENTRY_FAIL_DEFAULT;

@@ -3048,6 +3048,13 @@ static int nested_vmx_check_guest_state(struct kvm_vcpu *vcpu,
 					   vmcs12->guest_ia32_perf_global_ctrl)))
 		return -EINVAL;

+	if (CC((vmcs12->guest_cr0 & (X86_CR0_PG | X86_CR0_PE)) == X86_CR0_PG))
+		return -EINVAL;
+
+	if (CC(ia32e && !(vmcs12->guest_cr4 & X86_CR4_PAE)) ||
+	    CC(ia32e && !(vmcs12->guest_cr0 & X86_CR0_PG)))
+		return -EINVAL;
+
 	/*
 	 * If the load IA32_EFER VM-entry control is 1, the following checks
 	 * are performed on the field for the IA32_EFER MSR:
@@ -3059,7 +3066,6 @@ static int nested_vmx_check_guest_state(struct kvm_vcpu *vcpu,
 	 */
 	if (to_vmx(vcpu)->nested.nested_run_pending &&
 	    (vmcs12->vm_entry_controls & VM_ENTRY_LOAD_IA32_EFER)) {
-		ia32e = (vmcs12->vm_entry_controls & VM_ENTRY_IA32E_MODE) != 0;
 		if (CC(!kvm_valid_efer(vcpu, vmcs12->guest_ia32_efer)) ||
 		    CC(ia32e != !!(vmcs12->guest_ia32_efer & EFER_LMA)) ||
 		    CC(((vmcs12->guest_cr0 & X86_CR0_PG) &&


Have a common routine for converting dates and times to strings.

Have a routine that takes a buffer, a strftime format, and a struct tm *
as arguments, and:

* checks whether the struct tm * is null and, if so, returns a string
indicating that the date and time couldn't be converted;

* otherwise, passes it to strftime(), along with the buffer and the
format argument and, if strftime() returns 0, meaning the string didn't
fit into the buffer and thus that the buffer's contents are undefined,
returns a string indicating that the date and time didn't fit into the
buffer;

* otherwise, returns a pointer to the buffer.

Call that routine instead of directly calling strftime() in printers;
that prevents printing a buffer with undefined data if the buffer isn't
big enough for the string.

Also, when generating file names using an strftime format, check the
return value of strftime() to make sure the buffer didn't overflow.

@@ -423,6 +423,9 @@ extern void ts_print(netdissect_options *, const struct timeval *);
 extern void signed_relts_print(netdissect_options *, int32_t);
 extern void unsigned_relts_print(netdissect_options *, uint32_t);

+extern const char *nd_format_time(char *buf, size_t bufsize,
+    const char *format, const struct tm *timeptr);
+
 extern void fn_print_char(netdissect_options *, u_char);
 extern void fn_print_str(netdissect_options *, const u_char *);
 extern u_int nd_printztn(netdissect_options *, const u_char *, u_int, const u_char *);


@@ -22,6 +22,7 @@

 #define KiB(x) ((x)*1024)
 #define MiB(x) ((x)*1024 * 1024)
+#define BWT_BOUND(x) ((x) + 128)

 #include <inttypes.h>
 #include <stdint.h>


Check the neighbor_index in stl_check_normal_vector

Fixes #60

@@ -142,7 +142,8 @@ stl_fix_normal_directions(stl_file *stl) {
         }
       }
       /* If this edge of the facet is connected: */
-      if(stl->neighbors_start[facet_num].neighbor[j] != -1) {
+      if(stl->neighbors_start[facet_num].neighbor[j] != -1 &&
+         stl->neighbors_start[facet_num].neighbor[j] < stl->stats.number_of_facets*sizeof(char)) {
         /* If we haven't fixed this facet yet, add it to the list: */
         if(norm_sw[stl->neighbors_start[facet_num].neighbor[j]] != 1) {
           /* Add node to beginning of list. */


Merge pull request from GHSA-xjgw-7638-29g5

gnrc_rpl_srh: check header fields consistency before substraction

@@ -167,7 +167,7 @@ def test_wrong_type(child, iface, hw_dst, ll_dst, ll_src):
     pktbuf_empty(child)

-def test_seg_left_gt_len_addresses(child, iface, hw_dst, ll_dst, ll_src):
+def test_inconsistent_header(child, iface, hw_dst, ll_dst, ll_src):
     # send routing header with no (0) addresses but segleft set to a value
     # larger than 0
     p = srp1(Ether(dst=hw_dst) / IPv6(dst=ll_dst, src=ll_src) /
@@ -176,7 +176,7 @@ def test_seg_left_gt_len_addresses(child, iface, hw_dst, ll_dst, ll_src):
     assert(p is not None)
     assert(ICMPv6ParamProblem in p)
     assert(p[ICMPv6ParamProblem].code == 0)     # erroneous header field encountered
-    assert(p[ICMPv6ParamProblem].ptr == 43)     # segleft field
+    assert(p[ICMPv6ParamProblem].ptr == 41)     # len field
     pktbuf_empty(child)

@@ -348,7 +348,7 @@ def run(func):
                 raise e

     run(test_wrong_type)
-    run(test_seg_left_gt_len_addresses)
+    run(test_inconsistent_header)
     run(test_multicast_dst)
     run(test_multicast_addr)
     run(test_multiple_addrs_of_mine_uncomp)


Merge pull request from GHSA-8r8p-23f3-64c2

* segment random number generation into own file

* abstract random code to make it more modular so we can have multiple backends

* rand: add support for arc4random_buf() and also direct CARES_RANDOM_FILE reading

* autotools: fix detection of arc4random_buf

* rework initial rc4 seed for PRNG as last fallback

* rc4: more proper implementation, simplified for clarity

* clarifications

@@ -61,17 +61,6 @@
 #undef WIN32  /* Redefined in MingW/MSVC headers */
 #endif

-/* Define RtlGenRandom = SystemFunction036.  This is in advapi32.dll.  There is
- * no need to dynamically load this, other software used widely does not.
- * http://blogs.msdn.com/michael_howard/archive/2005/01/14/353379.aspx
- * https://docs.microsoft.com/en-us/windows/win32/api/ntsecapi/nf-ntsecapi-rtlgenrandom
- */
-#ifdef _WIN32
-BOOLEAN WINAPI SystemFunction036(PVOID RandomBuffer, ULONG RandomBufferLength);
-#  ifndef RtlGenRandom
-#    define RtlGenRandom(a,b) SystemFunction036(a,b)
-#  endif
-#endif

 static int init_by_options(ares_channel channel,
                            const struct ares_options *options,
@@ -87,7 +76,6 @@ static int config_nameserver(struct server_state **servers, int *nservers,
 static int set_search(ares_channel channel, const char *str);
 static int set_options(ares_channel channel, const char *str);
 static const char *try_option(const char *p, const char *q, const char *opt);
-static int init_id_key(rc4_key* key,int key_data_len);

 static int config_sortlist(struct apattern **sortlist, int *nsort,
                            const char *str);
@@ -165,6 +153,7 @@ int ares_init_options(ares_channel *channelptr, struct ares_options *options,
   channel->sock_func_cb_data = NULL;
   channel->resolvconf_path = NULL;
   channel->hosts_path = NULL;
+  channel->rand_state = NULL;

   channel->last_server = 0;
   channel->last_timeout_processed = (time_t)now.tv_sec;
@@ -218,9 +207,13 @@ int ares_init_options(ares_channel *channelptr, struct ares_options *options,
   /* Generate random key */

   if (status == ARES_SUCCESS) {
-    status = init_id_key(&channel->id_key, ARES_ID_KEY_LEN);
+    channel->rand_state = ares__init_rand_state();
+    if (channel->rand_state == NULL) {
+      status = ARES_ENOMEM;
+    }
+
     if (status == ARES_SUCCESS)
-      channel->next_id = ares__generate_new_id(&channel->id_key);
+      channel->next_id = ares__generate_new_id(channel->rand_state);
     else
       DEBUGF(fprintf(stderr, "Error: init_id_key failed: %s\n",
                      ares_strerror(status)));
@@ -242,6 +235,8 @@ int ares_init_options(ares_channel *channelptr, struct ares_options *options,
         ares_free(channel->resolvconf_path);
       if(channel->hosts_path)
         ares_free(channel->hosts_path);
+      if (channel->rand_state)
+        ares__destroy_rand_state(channel->rand_state);
       ares_free(channel);
       return status;
     }
@@ -2182,72 +2177,6 @@ static int sortlist_alloc(struct apattern **sortlist, int *nsort,
 }

-/* initialize an rc4 key. If possible a cryptographically secure random key
-   is generated using a suitable function otherwise the code defaults to
-   cross-platform albeit less secure mechanism using rand
-*/
-static void randomize_key(unsigned char* key,int key_data_len)
-{
-  int randomized = 0;
-  int counter=0;
-#ifdef WIN32
-  BOOLEAN res;
-
-  res = RtlGenRandom(key, key_data_len);
-  if (res)
-    randomized = 1;
-
-#else /* !WIN32 */
-#  ifdef CARES_RANDOM_FILE
-  FILE *f = fopen(CARES_RANDOM_FILE, "rb");
-  if(f) {
-    setvbuf(f, NULL, _IONBF, 0);
-    counter = aresx_uztosi(fread(key, 1, key_data_len, f));
-    fclose(f);
-  }
-#  endif
-#endif /* WIN32 */
-
-  if (!randomized) {
-    for (;counter<key_data_len;counter++)
-      key[counter]=(unsigned char)(rand() % 256);  /* LCOV_EXCL_LINE */
-  }
-}
-
-static int init_id_key(rc4_key* key,int key_data_len)
-{
-  unsigned char index1;
-  unsigned char index2;
-  unsigned char* state;
-  short counter;
-  unsigned char *key_data_ptr = 0;
-
-  key_data_ptr = ares_malloc(key_data_len);
-  if (!key_data_ptr)
-    return ARES_ENOMEM;
-  memset(key_data_ptr, 0, key_data_len);
-
-  state = &key->state[0];
-  for(counter = 0; counter < 256; counter++)
-    /* unnecessary AND but it keeps some compilers happier */
-    state[counter] = (unsigned char)(counter & 0xff);
-  randomize_key(key->state,key_data_len);
-  key->x = 0;
-  key->y = 0;
-  index1 = 0;
-  index2 = 0;
-  for(counter = 0; counter < 256; counter++)
-  {
-    index2 = (unsigned char)((key_data_ptr[index1] + state[counter] +
-                              index2) % 256);
-    ARES_SWAP_BYTE(&state[counter], &state[index2]);
-
-    index1 = (unsigned char)((index1 + 1) % key_data_len);
-  }
-  ares_free(key_data_ptr);
-  return ARES_SUCCESS;
-}
-
 void ares_set_local_ip4(ares_channel channel, unsigned int local_ip)
 {
   channel->local_ip4 = local_ip;


x86: get rid of small constant size cases in raw_copy_{to,from}_user()

Very few call sites where that would be triggered remain, and none
of those is anywhere near hot enough to bother.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>

@@ -23,33 +23,6 @@ raw_copy_to_user(void __user *to, const void *from, unsigned long n)
 static __always_inline unsigned long
 raw_copy_from_user(void *to, const void __user *from, unsigned long n)
 {
-	if (__builtin_constant_p(n)) {
-		unsigned long ret;
-
-		switch (n) {
-		case 1:
-			ret = 0;
-			__uaccess_begin_nospec();
-			__get_user_asm_nozero(*(u8 *)to, from, ret,
-					      "b", "b", "=q", 1);
-			__uaccess_end();
-			return ret;
-		case 2:
-			ret = 0;
-			__uaccess_begin_nospec();
-			__get_user_asm_nozero(*(u16 *)to, from, ret,
-					      "w", "w", "=r", 2);
-			__uaccess_end();
-			return ret;
-		case 4:
-			ret = 0;
-			__uaccess_begin_nospec();
-			__get_user_asm_nozero(*(u32 *)to, from, ret,
-					      "l", "k", "=r", 4);
-			__uaccess_end();
-			return ret;
-		}
-	}
 	return __copy_user_ll(to, (__force const void *)from, n);
 }


Revised handling of TIFFTAG_INKNAMES and related TIFFTAG_NUMBEROFINKS value

In order to solve the buffer overflow issues related to TIFFTAG_INKNAMES and related TIFFTAG_NUMBEROFINKS value, a revised handling of those tags within LibTiff is proposed:

Behaviour for writing:
    `NumberOfInks`  MUST fit to the number of inks in the `InkNames` string.
    `NumberOfInks` is automatically set when `InkNames` is set.
    If `NumberOfInks` is different to the number of inks within `InkNames` string, that will be corrected and a warning is issued.
    If `NumberOfInks` is not equal to samplesperpixel only a warning will be issued.

Behaviour for reading:
    When reading `InkNames` from a TIFF file, the `NumberOfInks` will be set automatically to the number of inks in `InkNames` string.
    If `NumberOfInks` is different to the number of inks within `InkNames` string, that will be corrected and a warning is issued.
    If  `NumberOfInks` is not equal to samplesperpixel only a warning will be issued.

This allows the safe use of the NumberOfInks value to read out the InkNames without buffer overflow

This MR will close the following issues:  #149, #150, #152, #168 (to be checked), #250, #269, #398 and #456.

It also fixes the old bug at http://bugzilla.maptools.org/show_bug.cgi?id=2599, for which the limitation of `NumberOfInks = SPP` was introduced, which is in my opinion not necessary and does not solve the general issue.

@@ -136,32 +136,30 @@ setExtraSamples(TIFF* tif, va_list ap, uint32_t* v)
 }

 /*
- * Confirm we have "samplesperpixel" ink names separated by \0.  Returns
+ * Count ink names separated by \0.  Returns
  * zero if the ink names are not as expected.
  */
-static uint32_t
-checkInkNamesString(TIFF* tif, uint32_t slen, const char* s)
+static uint16_t
+countInkNamesString(TIFF *tif, uint32_t slen, const char *s)
 {
-	TIFFDirectory* td = &tif->tif_dir;
-	uint16_t i = td->td_samplesperpixel;
+	uint16_t i = 0;
+	const char *ep = s + slen;
+	const char *cp = s;

 	if (slen > 0) {
-		const char* ep = s+slen;
-		const char* cp = s;
-		for (; i > 0; i--) {
+		do {
 			for (; cp < ep && *cp != '\0'; cp++) {}
 			if (cp >= ep)
 				goto bad;
 			cp++;				/* skip \0 */
-		}
-		return ((uint32_t)(cp - s));
+			i++;
+		} while (cp < ep);
+		return (i);
 	}
 bad:
 	TIFFErrorExt(tif->tif_clientdata, "TIFFSetField",
-	    "%s: Invalid InkNames value; expecting %"PRIu16" names, found %"PRIu16,
-	    tif->tif_name,
-	    td->td_samplesperpixel,
-	    (uint16_t)(td->td_samplesperpixel-i));
+		"%s: Invalid InkNames value; no NUL at given buffer end location %"PRIu32", after %"PRIu16" ink",
+		tif->tif_name, slen, i);
 	return (0);
 }

@@ -478,13 +476,61 @@ _TIFFVSetField(TIFF* tif, uint32_t tag, va_list ap)
 		_TIFFsetFloatArray(&td->td_refblackwhite, va_arg(ap, float*), 6);
 		break;
 	case TIFFTAG_INKNAMES:
-		v = (uint16_t) va_arg(ap, uint16_vap);
-		s = va_arg(ap, char*);
-		v = checkInkNamesString(tif, v, s);
-		status = v > 0;
-		if( v > 0 ) {
-			_TIFFsetNString(&td->td_inknames, s, v);
-			td->td_inknameslen = v;
+		{
+			v = (uint16_t) va_arg(ap, uint16_vap);
+			s = va_arg(ap, char*);
+			uint16_t ninksinstring;
+			ninksinstring = countInkNamesString(tif, v, s);
+			status = ninksinstring > 0;
+			if(ninksinstring > 0 ) {
+				_TIFFsetNString(&td->td_inknames, s, v);
+				td->td_inknameslen = v;
+				/* Set NumberOfInks to the value ninksinstring */
+				if (TIFFFieldSet(tif, FIELD_NUMBEROFINKS))
+				{
+					if (td->td_numberofinks != ninksinstring) {
+						TIFFErrorExt(tif->tif_clientdata, module,
+							"Warning %s; Tag %s:\n  Value %"PRIu16" of NumberOfInks is different from the number of inks %"PRIu16".\n  -> NumberOfInks value adapted to %"PRIu16"",
+							tif->tif_name, fip->field_name, td->td_numberofinks, ninksinstring, ninksinstring);
+						td->td_numberofinks = ninksinstring;
+					}
+				} else {
+					td->td_numberofinks = ninksinstring;
+					TIFFSetFieldBit(tif, FIELD_NUMBEROFINKS);
+				}
+				if (TIFFFieldSet(tif, FIELD_SAMPLESPERPIXEL))
+				{
+					if (td->td_numberofinks != td->td_samplesperpixel) {
+						TIFFErrorExt(tif->tif_clientdata, module,
+							"Warning %s; Tag %s:\n  Value %"PRIu16" of NumberOfInks is different from the SamplesPerPixel value %"PRIu16"",
+							tif->tif_name, fip->field_name, td->td_numberofinks, td->td_samplesperpixel);
+					}
+				}
+			}
+		}
+		break;
+	case TIFFTAG_NUMBEROFINKS:
+		v = (uint16_t)va_arg(ap, uint16_vap);
+		/* If InkNames already set also NumberOfInks is set accordingly and should be equal */
+		if (TIFFFieldSet(tif, FIELD_INKNAMES))
+		{
+			if (v != td->td_numberofinks) {
+				TIFFErrorExt(tif->tif_clientdata, module,
+					"Error %s; Tag %s:\n  It is not possible to set the value %"PRIu32" for NumberOfInks\n  which is different from the number of inks in the InkNames tag (%"PRIu16")",
+					tif->tif_name, fip->field_name, v, td->td_numberofinks);
+				/* Do not set / overwrite number of inks already set by InkNames case accordingly. */
+				status = 0;
+			}
+		} else {
+			td->td_numberofinks = (uint16_t)v;
+			if (TIFFFieldSet(tif, FIELD_SAMPLESPERPIXEL))
+			{
+				if (td->td_numberofinks != td->td_samplesperpixel) {
+					TIFFErrorExt(tif->tif_clientdata, module,
+						"Warning %s; Tag %s:\n  Value %"PRIu32" of NumberOfInks is different from the SamplesPerPixel value %"PRIu16"",
+						tif->tif_name, fip->field_name, v, td->td_samplesperpixel);
+				}
+			}
 		}
 		break;
 	case TIFFTAG_PERSAMPLE:
@@ -986,34 +1032,6 @@ _TIFFVGetField(TIFF* tif, uint32_t tag, va_list ap)
 	if (fip->field_bit == FIELD_CUSTOM) {
 		standard_tag = 0;
 	}
-
-        if( standard_tag == TIFFTAG_NUMBEROFINKS )
-        {
-            int i;
-            for (i = 0; i < td->td_customValueCount; i++) {
-                uint16_t val;
-                TIFFTagValue *tv = td->td_customValues + i;
-                if (tv->info->field_tag != standard_tag)
-                    continue;
-                if( tv->value == NULL )
-                    return 0;
-                val = *(uint16_t *)tv->value;
-                /* Truncate to SamplesPerPixel, since the */
-                /* setting code for INKNAMES assume that there are SamplesPerPixel */
-                /* inknames. */
-                /* Fixes http://bugzilla.maptools.org/show_bug.cgi?id=2599 */
-                if( val > td->td_samplesperpixel )
-                {
-                    TIFFWarningExt(tif->tif_clientdata,"_TIFFVGetField",
-                                   "Truncating NumberOfInks from %u to %"PRIu16,
-                                   val, td->td_samplesperpixel);
-                    val = td->td_samplesperpixel;
-                }
-                *va_arg(ap, uint16_t*) = val;
-                return 1;
-            }
-            return 0;
-        }

 	switch (standard_tag) {
 		case TIFFTAG_SUBFILETYPE:
@@ -1195,6 +1213,9 @@ _TIFFVGetField(TIFF* tif, uint32_t tag, va_list ap)
 		case TIFFTAG_INKNAMES:
 			*va_arg(ap, const char**) = td->td_inknames;
 			break;
+		case TIFFTAG_NUMBEROFINKS:
+			*va_arg(ap, uint16_t *) = td->td_numberofinks;
+			break;
 		default:
 			{
 				int i;


Merge pull request from GHSA-gpxc-v2m8-fr3x

* beh backend: Use execv() instead of system() - CVE-2023-24805

With execv() command line arguments are passed as separate strings and
not the full command line in a single string. This prevents arbitrary
command execution by escaping the quoting of the arguments in a job
with forged job title.

* beh backend: Extra checks against odd/forged input - CVE-2023-24805

- Do not allow '/' in the scheme of the URI (= backend executable
  name), to assure that only backends inside /usr/lib/cups/backend/
  are used.

- Pre-define scheme buffer to empty string, to be defined for case of
  uri being NULL.

- URI must have ':', to split off scheme, otherwise error.

- Check return value of snprintf() to create call path for backend, to
  error out on truncation of a too long scheme or on complete failure
  due to a completely odd scheme.

* beh backend: Further improvements - CVE-2023-24805

- Use strncat() instead of strncpy() for getting scheme from URI, the latter
  does not require setting terminating zero byte in case of truncation.

- Also exclude "." or ".." as scheme, as directories are not valid CUPS
  backends.

- Do not use fprintf() in sigterm_handler(), to not interfere with a
  fprintf() which could be running in the main process when
  sigterm_handler() is triggered.

- Use "static volatile int" for global variable job_canceled.

@@ -26,13 +26,14 @@
 #include <signal.h>
 #include <string.h>
 #include <errno.h>
+#include <sys/wait.h>

 //
 // Local globals...
 //

-static int		job_canceled = 0; // Set to 1 on SIGTERM
+static volatile int	job_canceled = 0; // Set to 1 on SIGTERM

 //
@@ -237,21 +238,44 @@ call_backend(char *uri,                 // I - URI of final destination
 	     char *filename)            // I - File name of input data
 {
   const char	*cups_serverbin;	// Location of programs
+  char          *backend_argv[8];       // Arguments for called CUPS backend
   char		scheme[1024],           // Scheme from URI
                 *ptr,			// Pointer into scheme
-		cmdline[65536];		// Backend command line
-  int           retval;
+		backend_path[2048];	// Backend path
+  int           pid,
+                wait_pid,
+                wait_status,
+                retval = 0;
+  int           bytes;
+

   //
   // Build the backend command line...
   //

-  strncpy(scheme, uri, sizeof(scheme) - 1);
-  if (strlen(uri) > 1023)
-    scheme[1023] = '\0';
+  scheme[0] = '\0';
+  strncat(scheme, uri, sizeof(scheme) - 1);
   if ((ptr = strchr(scheme, ':')) != NULL)
     *ptr = '\0';
-
+  else
+  {
+    fprintf(stderr,
+	    "ERROR: beh: Invalid URI, no colon (':') to mark end of scheme part.\n");
+    exit (CUPS_BACKEND_FAILED);
+  }
+  if (strchr(scheme, '/'))
+  {
+    fprintf(stderr,
+	    "ERROR: beh: Invalid URI, scheme contains a slash ('/').\n");
+    exit (CUPS_BACKEND_FAILED);
+  }
+  if (!strcmp(scheme, ".") || !strcmp(scheme, ".."))
+  {
+    fprintf(stderr,
+	    "ERROR: beh: Invalid URI, scheme (\"%s\") is a directory.\n",
+	    scheme);
+    exit (CUPS_BACKEND_FAILED);
+  }
   if ((cups_serverbin = getenv("CUPS_SERVERBIN")) == NULL)
     cups_serverbin = CUPS_SERVERBIN;

@@ -261,16 +285,25 @@ call_backend(char *uri,                 // I - URI of final destination
 	    "ERROR: beh: Direct output into a file not supported.\n");
     exit (CUPS_BACKEND_FAILED);
   }
-  else
-    snprintf(cmdline, sizeof(cmdline),
-	     "%s/backend/%s '%s' '%s' '%s' '%s' '%s' %s",
-	     cups_serverbin, scheme, argv[1], argv[2], argv[3],
-	     // Apply number of copies only if beh was called with a
-	     // file name and not with the print data in stdin, as
-	     // backends should handle copies only if they are called
-	     // with a file name
-	     (argc == 6 ? "1" : argv[4]),
-	     argv[5], filename);
+
+  backend_argv[0] = uri;
+  backend_argv[1] = argv[1];
+  backend_argv[2] = argv[2];
+  backend_argv[3] = argv[3];
+  backend_argv[4] = (argc == 6 ? "1" : argv[4]);
+  backend_argv[5] = argv[5];
+  backend_argv[6] = filename;
+  backend_argv[7] = NULL;
+
+  bytes = snprintf(backend_path, sizeof(backend_path),
+		   "%s/backend/%s", cups_serverbin, scheme);
+  if (bytes < 0 || bytes >= sizeof(backend_path))
+  {
+    fprintf(stderr,
+	    "ERROR: beh: Invalid scheme (\"%s\"), could not determing backend path.\n",
+	    scheme);
+    exit (CUPS_BACKEND_FAILED);
+  }

   //
   // Overwrite the device URI and run the actual backend...
@@ -279,17 +312,41 @@ call_backend(char *uri,                 // I - URI of final destination
   setenv("DEVICE_URI", uri, 1);

   fprintf(stderr,
-	  "DEBUG: beh: Executing backend command line \"%s\"...\n",
-	  cmdline);
+	  "DEBUG: beh: Executing backend command line \"%s '%s' '%s' '%s' '%s' '%s'%s%s\"...\n",
+	  backend_path, backend_argv[1], backend_argv[2], backend_argv[3],
+	  backend_argv[4], backend_argv[5],
+	  (backend_argv[6] && backend_argv[6][0] ? " " : ""),
+	  (backend_argv[6] && backend_argv[6][0] ? backend_argv[6] : ""));
   fprintf(stderr,
 	  "DEBUG: beh: Using device URI: %s\n",
 	  uri);

-  retval = system(cmdline) >> 8;
+  if ((pid = fork()) == 0)
+  {
+    retval = execv(backend_path, backend_argv);

-  if (retval == -1)
-    fprintf(stderr, "ERROR: Unable to execute backend command line: %s\n",
-	    strerror(errno));
+    if (retval == -1)
+      fprintf(stderr, "ERROR: Unable to execute backend: %s\n",
+	      strerror(errno));
+    exit (CUPS_BACKEND_FAILED);
+  }
+  else if (pid < 0)
+  {
+    fprintf(stderr, "ERROR: Unable to fork for backend\n");
+    return (CUPS_BACKEND_FAILED);
+  }
+
+  while ((wait_pid = wait(&wait_status)) < 0 && errno == EINTR);
+
+  if (wait_pid >= 0 && wait_status)
+  {
+    if (WIFEXITED(wait_status))
+      retval = WEXITSTATUS(wait_status);
+    else if (WTERMSIG(wait_status) != SIGTERM)
+      retval = WTERMSIG(wait_status);
+    else
+      retval = 0;
+  }

   return (retval);
 }
@@ -304,8 +361,10 @@ sigterm_handler(int sig)		// I - Signal number (unused)
 {
   (void)sig;

-  fprintf(stderr,
-	  "DEBUG: beh: Job canceled.\n");
+  const char * const msg = "DEBUG: beh: Job canceled.\n";
+  // The if() is to eliminate the return value and silence the warning
+  // about an unused return value.
+  if (write(2, msg, strlen(msg)));

   if (job_canceled)
     _exit(CUPS_BACKEND_OK);


netfilter: nf_tables: deactivate anonymous set from preparation phase

Toggle deleted anonymous sets as inactive in the next generation, so
users cannot perform any update on it. Clear the generation bitmask
in case the transaction is aborted.

The following KASAN splat shows a set element deletion for a bound
anonymous set that has been already removed in the same transaction.

[   64.921510] ==================================================================
[   64.923123] BUG: KASAN: wild-memory-access in nf_tables_commit+0xa24/0x1490 [nf_tables]
[   64.924745] Write of size 8 at addr dead000000000122 by task test/890
[   64.927903] CPU: 3 PID: 890 Comm: test Not tainted 6.3.0+ #253
[   64.931120] Call Trace:
[   64.932699]  <TASK>
[   64.934292]  dump_stack_lvl+0x33/0x50
[   64.935908]  ? nf_tables_commit+0xa24/0x1490 [nf_tables]
[   64.937551]  kasan_report+0xda/0x120
[   64.939186]  ? nf_tables_commit+0xa24/0x1490 [nf_tables]
[   64.940814]  nf_tables_commit+0xa24/0x1490 [nf_tables]
[   64.942452]  ? __kasan_slab_alloc+0x2d/0x60
[   64.944070]  ? nf_tables_setelem_notify+0x190/0x190 [nf_tables]
[   64.945710]  ? kasan_set_track+0x21/0x30
[   64.947323]  nfnetlink_rcv_batch+0x709/0xd90 [nfnetlink]
[   64.948898]  ? nfnetlink_rcv_msg+0x480/0x480 [nfnetlink]

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>

@@ -185,7 +185,7 @@ static void nft_objref_map_activate(const struct nft_ctx *ctx,
 {
 	struct nft_objref_map *priv = nft_expr_priv(expr);

-	priv->set->use++;
+	nf_tables_activate_set(ctx, priv->set);
 }

 static void nft_objref_map_destroy(const struct nft_ctx *ctx,