static char *lxclock_name(const char *p, const char *n)
{
	int ret;
	int len;
	char *dest;
	char *rundir;

	/* lockfile will be:
	 * "/run" + "/lxc/lock/$lxcpath/$lxcname + '\0' if root
	 * or
	 * $XDG_RUNTIME_DIR + "/lxc/lock/$lxcpath/$lxcname + '\0' if non-root
	 */

	/* length of "/lxc/lock/" + $lxcpath + "/" + $lxcname + '\0' */
	len = strlen("/lxc/lock/") + strlen(n) + strlen(p) + 2;
	rundir = get_rundir();
	if (!rundir)
		return NULL;
	len += strlen(rundir);

	if ((dest = malloc(len)) == NULL) {
		free(rundir);
		return NULL;
	}

	ret = snprintf(dest, len, "%s/lxc/lock/%s", rundir, p);
	if (ret < 0 || ret >= len) {
		free(dest);
		free(rundir);
		return NULL;
	}
	ret = mkdir_p(dest, 0755);
	if (ret < 0) {
		free(dest);
		free(rundir);
		return NULL;
	}

	ret = snprintf(dest, len, "%s/lxc/lock/%s/%s", rundir, p, n);
	free(rundir);
	if (ret < 0 || ret >= len) {
		free(dest);
		return NULL;
	}
	return dest;
}


webm2pes: Avoid OOB reads caused by invalid superframe index.

BUG=webm:1492

Change-Id: Ibd5781731fe8f6fcdf5f1cc6e5807d17b3b92d4d

bool ParseVP9SuperFrameIndex(const std::uint8_t* frame,
                             std::size_t frame_length, Ranges* frame_ranges) {
  if (frame == nullptr || frame_length == 0 || frame_ranges == nullptr)
    return false;

  bool parse_ok = false;
  const std::uint8_t marker = frame[frame_length - 1];
  const std::uint32_t kHasSuperFrameIndexMask = 0xe0;
  const std::uint32_t kSuperFrameMarker = 0xc0;
  const std::uint32_t kLengthFieldSizeMask = 0x3;

  if ((marker & kHasSuperFrameIndexMask) == kSuperFrameMarker) {
    const std::uint32_t kFrameCountMask = 0x7;
    const int num_frames = (marker & kFrameCountMask) + 1;
    const int length_field_size = ((marker >> 3) & kLengthFieldSizeMask) + 1;
    const std::size_t index_length = 2 + length_field_size * num_frames;

    if (frame_length < index_length) {
      std::fprintf(stderr, "VP9Parse: Invalid superframe index size.\n");
      return false;
    }

    // Consume the super frame index. Note: it's at the end of the super frame.
    const std::size_t length = frame_length - index_length;

    if (length >= index_length &&
        frame[frame_length - index_length] == marker) {
      // Found a valid superframe index.
      const std::uint8_t* byte = frame + length + 1;

      std::size_t frame_offset = 0;
      for (int i = 0; i < num_frames; ++i) {
        std::uint32_t child_frame_length = 0;

        for (int j = 0; j < length_field_size; ++j) {
          child_frame_length |= (*byte++) << (j * 8);
        }

        frame_ranges->push_back(Range(frame_offset, child_frame_length));
        frame_offset += child_frame_length;
      }

      if (static_cast<int>(frame_ranges->size()) != num_frames) {
        std::fprintf(stderr, "VP9Parse: superframe index parse failed.\n");
        return false;
      }

      parse_ok = true;
    } else {
      std::fprintf(stderr, "VP9Parse: Invalid superframe index.\n");
    }
  }
  return parse_ok;
}

The function ParseVP9SuperFrameIndex in common/libwebm_util.cc in libwebm through 2018-01-30 does not validate the child_frame_length data obtained from a .webm file, which allows remote attackers to cause an information leak or a denial of service (heap-based buffer over-read and later out-of-bounds write), or possibly have unspecified other impact.


bool ParseVP9SuperFrameIndex(const std::uint8_t* frame,
                             std::size_t frame_length, Ranges* frame_ranges,
                             bool* error) {
  if (frame == nullptr || frame_length == 0 || frame_ranges == nullptr ||
      error == nullptr) {
    return false;
  }

  bool parse_ok = false;
  const std::uint8_t marker = frame[frame_length - 1];
  const std::uint32_t kHasSuperFrameIndexMask = 0xe0;
  const std::uint32_t kSuperFrameMarker = 0xc0;
  const std::uint32_t kLengthFieldSizeMask = 0x3;

  if ((marker & kHasSuperFrameIndexMask) == kSuperFrameMarker) {
    const std::uint32_t kFrameCountMask = 0x7;
    const int num_frames = (marker & kFrameCountMask) + 1;
    const int length_field_size = ((marker >> 3) & kLengthFieldSizeMask) + 1;
    const std::size_t index_length = 2 + length_field_size * num_frames;

    if (frame_length < index_length) {
      std::fprintf(stderr,
                   "VP9ParseSuperFrameIndex: Invalid superframe index size.\n");
      *error = true;
      return false;
    }

    // Consume the super frame index. Note: it's at the end of the super frame.
    const std::size_t length = frame_length - index_length;

    if (length >= index_length &&
        frame[frame_length - index_length] == marker) {
      // Found a valid superframe index.
      const std::uint8_t* byte = frame + length + 1;

      std::size_t frame_offset = 0;

      for (int i = 0; i < num_frames; ++i) {
        std::uint32_t child_frame_length = 0;

        for (int j = 0; j < length_field_size; ++j) {
          child_frame_length |= (*byte++) << (j * 8);
        }

        if (length - frame_offset < child_frame_length) {
          std::fprintf(stderr,
                       "ParseVP9SuperFrameIndex: Invalid superframe, sub frame "
                       "larger than entire frame.\n");
          *error = true;
          return false;
        }

        frame_ranges->push_back(Range(frame_offset, child_frame_length));
        frame_offset += child_frame_length;
      }

      if (static_cast<int>(frame_ranges->size()) != num_frames) {
        std::fprintf(stderr, "VP9Parse: superframe index parse failed.\n");
        *error = true;
        return false;
      }

      parse_ok = true;
    } else {
      std::fprintf(stderr, "VP9Parse: Invalid superframe index.\n");
      *error = true;
    }
  }
  return parse_ok;
}


AD: process non-posix nested groups w/o tokenGroups

When initgr is performed for AD not supporting tokenGroups, do not
filter out groups without gid attribute or with gid equal to zero.

Resolves:
https://fedorahosted.org/sssd/ticket/2343

Reviewed-by: Michal Židek <mzidek@redhat.com>
(cherry picked from commit 981bf55532fbec91a106f82d7daf32094c76dfe0)

static struct tevent_req *sdap_initgr_rfc2307bis_send(
        TALLOC_CTX *memctx,
        struct tevent_context *ev,
        struct sdap_options *opts,
        struct sdap_domain *sdom,
        struct sdap_handle *sh,
        const char *name,
        const char *orig_dn)
{
    errno_t ret;
    struct tevent_req *req;
    struct sdap_initgr_rfc2307bis_state *state;
    const char **attr_filter;
    char *clean_orig_dn;
    bool use_id_mapping;

    req = tevent_req_create(memctx, &state, struct sdap_initgr_rfc2307bis_state);
    if (!req) return NULL;

    state->ev = ev;
    state->opts = opts;
    state->sysdb = sdom->dom->sysdb;
    state->dom = sdom->dom;
    state->sh = sh;
    state->op = NULL;
    state->name = name;
    state->direct_groups = NULL;
    state->num_direct_parents = 0;
    state->timeout = dp_opt_get_int(state->opts->basic, SDAP_SEARCH_TIMEOUT);
    state->base_iter = 0;
    state->search_bases = sdom->group_search_bases;
    state->orig_dn = orig_dn;

    if (!state->search_bases) {
        DEBUG(SSSDBG_CRIT_FAILURE,
              "Initgroups lookup request without a group search base\n");
        ret = EINVAL;
        goto done;
    }

    ret = sss_hash_create(state, 32, &state->group_hash);
    if (ret != EOK) {
        talloc_free(req);
        return NULL;
    }

    attr_filter = talloc_array(state, const char *, 2);
    if (!attr_filter) {
        ret = ENOMEM;
        goto done;
    }

    attr_filter[0] = opts->group_map[SDAP_AT_GROUP_MEMBER].name;
    attr_filter[1] = NULL;

    ret = build_attrs_from_map(state, opts->group_map, SDAP_OPTS_GROUP,
                               attr_filter, &state->attrs, NULL);
    if (ret != EOK) goto done;

    ret = sss_filter_sanitize(state, orig_dn, &clean_orig_dn);
    if (ret != EOK) goto done;

    use_id_mapping = sdap_idmap_domain_has_algorithmic_mapping(
                                                        opts->idmap_ctx,
                                                        sdom->dom->name,
                                                        sdom->dom->domain_id);

    state->base_filter =
            talloc_asprintf(state, "(&(%s=%s)(objectclass=%s)(%s=*)",
                            opts->group_map[SDAP_AT_GROUP_MEMBER].name,
                            clean_orig_dn,
                            opts->group_map[SDAP_OC_GROUP].name,
                            opts->group_map[SDAP_AT_GROUP_NAME].name);
    if (!state->base_filter) {
        ret = ENOMEM;
        goto done;
    }

    if (use_id_mapping) {
        /* When mapping IDs or looking for SIDs, we don't want to limit
         * ourselves to groups with a GID value. But there must be a SID to map
         * from.
         */
        state->base_filter = talloc_asprintf_append(state->base_filter,
                                        "(%s=*))",
                                        opts->group_map[SDAP_AT_GROUP_OBJECTSID].name);
    } else {
        /* When not ID-mapping, make sure there is a non-NULL UID */
        state->base_filter = talloc_asprintf_append(state->base_filter,
                                        "(&(%s=*)(!(%s=0))))",
                                        opts->group_map[SDAP_AT_GROUP_GID].name,
                                        opts->group_map[SDAP_AT_GROUP_GID].name);
    }
    if (!state->base_filter) {
        talloc_zfree(req);
        return NULL;
    }

    talloc_zfree(clean_orig_dn);

    ret = sdap_initgr_rfc2307bis_next_base(req);

done:
    if (ret != EOK) {
        tevent_req_error(req, ret);
        tevent_req_post(req, ev);
    }
    return req;
}

The System Security Services Daemon (SSSD) 1.11.6 does not properly identify group membership when a non-POSIX group is in a group membership chain, which allows local users to bypass access restrictions via unspecified vectors.


static struct tevent_req *sdap_initgr_rfc2307bis_send(
        TALLOC_CTX *memctx,
        struct tevent_context *ev,
        struct sdap_options *opts,
        struct sdap_domain *sdom,
        struct sdap_handle *sh,
        const char *name,
        const char *orig_dn)
{
    errno_t ret;
    struct tevent_req *req;
    struct sdap_initgr_rfc2307bis_state *state;
    const char **attr_filter;
    char *clean_orig_dn;
    bool use_id_mapping;

    req = tevent_req_create(memctx, &state, struct sdap_initgr_rfc2307bis_state);
    if (!req) return NULL;

    state->ev = ev;
    state->opts = opts;
    state->sysdb = sdom->dom->sysdb;
    state->dom = sdom->dom;
    state->sh = sh;
    state->op = NULL;
    state->name = name;
    state->direct_groups = NULL;
    state->num_direct_parents = 0;
    state->timeout = dp_opt_get_int(state->opts->basic, SDAP_SEARCH_TIMEOUT);
    state->base_iter = 0;
    state->search_bases = sdom->group_search_bases;
    state->orig_dn = orig_dn;

    if (!state->search_bases) {
        DEBUG(SSSDBG_CRIT_FAILURE,
              "Initgroups lookup request without a group search base\n");
        ret = EINVAL;
        goto done;
    }

    ret = sss_hash_create(state, 32, &state->group_hash);
    if (ret != EOK) {
        talloc_free(req);
        return NULL;
    }

    attr_filter = talloc_array(state, const char *, 2);
    if (!attr_filter) {
        ret = ENOMEM;
        goto done;
    }

    attr_filter[0] = opts->group_map[SDAP_AT_GROUP_MEMBER].name;
    attr_filter[1] = NULL;

    ret = build_attrs_from_map(state, opts->group_map, SDAP_OPTS_GROUP,
                               attr_filter, &state->attrs, NULL);
    if (ret != EOK) goto done;

    ret = sss_filter_sanitize(state, orig_dn, &clean_orig_dn);
    if (ret != EOK) goto done;

    use_id_mapping = sdap_idmap_domain_has_algorithmic_mapping(
                                                        opts->idmap_ctx,
                                                        sdom->dom->name,
                                                        sdom->dom->domain_id);

    state->base_filter =
            talloc_asprintf(state, "(&(%s=%s)(objectclass=%s)(%s=*)",
                            opts->group_map[SDAP_AT_GROUP_MEMBER].name,
                            clean_orig_dn,
                            opts->group_map[SDAP_OC_GROUP].name,
                            opts->group_map[SDAP_AT_GROUP_NAME].name);
    if (!state->base_filter) {
        ret = ENOMEM;
        goto done;
    }

    if (use_id_mapping) {
        /* When mapping IDs or looking for SIDs, we don't want to limit
         * ourselves to groups with a GID value. But there must be a SID to map
         * from.
         */
        state->base_filter = talloc_asprintf_append(state->base_filter,
                                        "(%s=*))",
                                        opts->group_map[SDAP_AT_GROUP_OBJECTSID].name);
    } else {
        state->base_filter = talloc_asprintf_append(state->base_filter, ")");
    }
    if (!state->base_filter) {
        talloc_zfree(req);
        return NULL;
    }

    talloc_zfree(clean_orig_dn);

    ret = sdap_initgr_rfc2307bis_next_base(req);

done:
    if (ret != EOK) {
        tevent_req_error(req, ret);
        tevent_req_post(req, ev);
    }
    return req;
}


bb19798 - fix out of bound memory access for crafted wwunpack file.

int wwunpack(uint8_t *exe, uint32_t exesz, uint8_t *wwsect, struct cli_exe_section *sects, uint16_t scount, uint32_t pe, int desc) {
  uint8_t *structs = wwsect + 0x2a1, *compd, *ccur, *unpd, *ucur, bc;
  uint32_t src, srcend, szd, bt, bits;
  int error=0, i;

  cli_dbgmsg("in wwunpack\n");
  while (1) {
    if (!CLI_ISCONTAINED(wwsect, sects[scount].rsz, structs, 17)) {
      cli_dbgmsg("WWPack: Array of structs out of section\n");
      break;
    }
    src = sects[scount].rva - cli_readint32(structs); /* src delta / dst delta - not used / dwords / end of src */
    structs+=8;
    szd = cli_readint32(structs) * 4;
    structs+=4;
    srcend = cli_readint32(structs);
    structs+=4;

    unpd = ucur = exe+src+srcend+4-szd;
    if (!szd || !CLI_ISCONTAINED(exe, exesz, unpd, szd)) {
      cli_dbgmsg("WWPack: Compressed data out of file\n");
      break;
    }
    cli_dbgmsg("WWP: src: %x, szd: %x, srcend: %x - %x\n", src, szd, srcend, srcend+4-szd);
    if (!(compd = cli_malloc(szd))) {
        cli_dbgmsg("WWPack: Unable to allocate memory for compd\n");
        break;
    }
    memcpy(compd, unpd, szd);
    memset(unpd, -1, szd); /*FIXME*/
    ccur=compd;

    RESEED;
    while(!error) {
      uint32_t backbytes, backsize;
      uint8_t saved;

      BIT;
      if (!bits) { /* BYTE copy */
	if(ccur-compd>=szd || !CLI_ISCONTAINED(exe, exesz, ucur, 1))
	  error=1;
	else
	  *ucur++=*ccur++;
	continue;
      }

      BITS(2);
      if(bits==3) { /* WORD backcopy */
	uint8_t shifted, subbed = 31;
	BITS(2);
	shifted = bits + 5;
	if(bits>=2) {
	  shifted++;
	  subbed += 0x80;
	}
	backbytes = (1<<shifted)-subbed; /* 1h, 21h, 61h, 161h */
	BITS(shifted); /* 5, 6, 8, 9 */
	if(error || bits == 0x1ff) break;
	backbytes+=bits;
	if(!CLI_ISCONTAINED(exe, exesz, ucur, 2) || !CLI_ISCONTAINED(exe, exesz, ucur-backbytes, 2)) {
	  error=1;
	} else {
	  ucur[0]=*(ucur-backbytes);
	  ucur[1]=*(ucur-backbytes+1);
	  ucur+=2;
	}
	continue;
      }

      /* BLOCK backcopy */
      saved = bits; /* cmp al, 1 / pushf */

      BITS(3);
      if (bits<6) {
	backbytes = bits;
	switch(bits) {
	case 4: /* 10,11 */
	  backbytes++;
	case 3: /* 8,9 */
	  BIT;
	  backbytes+=bits;
	case 0:	case 1:	case 2: /* 5,6,7 */
	  backbytes+=5;
	  break;
	case 5: /* 12 */
	  backbytes=12;
	  break;
	}
	BITS(backbytes);
	bits+=(1<<backbytes)-31;
      } else if(bits==6) {
	BITS(0x0e);
	bits+=0x1fe1;
      } else {
	BITS(0x0f);
	bits+=0x5fe1;
      }

      backbytes = bits;

      /* popf / jb */
      if (!saved) {
	BIT;
	if(!bits) {
	  BIT;
	  bits+=5;
	} else {
	  BITS(3);
	  if(bits) {
	    bits+=6;
	  } else {
	    BITS(4);
	    if(bits) {
	      bits+=13;
	    } else {
	      uint8_t cnt = 4;
	      uint16_t shifted = 0x0d;

	      do {
		if(cnt==7) { cnt = 0x0e; shifted = 0; break; }
		shifted=((shifted+2)<<1)-1;
		BIT;
		cnt++;
	      } while(!bits);
	      BITS(cnt);
	      bits+=shifted;
	    }
	  }
	}
	backsize = bits;
      } else {
	backsize = saved+2;
      }

      if(!CLI_ISCONTAINED(exe, exesz, ucur, backsize) || !CLI_ISCONTAINED(exe, exesz, ucur-backbytes, backsize)) error=1;
      else while(backsize--) {
	*ucur=*(ucur-backbytes);
	ucur++;
      }
    }
    free(compd);
    if(error) {
      cli_dbgmsg("WWPack: decompression error\n");
      break;
    }
    if (error || !*structs++) break;
  }

  if(!error) {
    if (pe+6 > exesz || pe+7 > exesz || pe+0x28 > exesz ||
		pe+0x50 > exesz || pe+0x14 > exesz)
	return CL_EFORMAT;
    exe[pe+6]=(uint8_t)scount;
    exe[pe+7]=(uint8_t)(scount>>8);
    cli_writeint32(&exe[pe+0x28], cli_readint32(wwsect+0x295)+sects[scount].rva+0x299);
    cli_writeint32(&exe[pe+0x50], cli_readint32(&exe[pe+0x50])-sects[scount].vsz);

    structs = &exe[(0xffff&cli_readint32(&exe[pe+0x14]))+pe+0x18];
    for(i=0 ; i<scount ; i++) {
	  if (!CLI_ISCONTAINED(exe, exesz, structs, 0x28)) {
	    cli_dbgmsg("WWPack: structs pointer out of bounds\n");
	    return CL_EFORMAT;
	  }

      cli_writeint32(structs+8, sects[i].vsz);
      cli_writeint32(structs+12, sects[i].rva);
      cli_writeint32(structs+16, sects[i].vsz);
      cli_writeint32(structs+20, sects[i].rva);
      structs+=0x28;
    }
	if (!CLI_ISCONTAINED(exe, exesz, structs, 0x28)) {
	  cli_dbgmsg("WWPack: structs pointer out of bounds\n");
	  return CL_EFORMAT;
	}

    memset(structs, 0, 0x28);
    error = (uint32_t)cli_writen(desc, exe, exesz)!=exesz;
  }
  return error;
}

The wwunpack function in libclamav/wwunpack.c in ClamAV 0.99.2 allows remote attackers to cause a denial of service (use-after-free) via a crafted PE file with WWPack compression.


int wwunpack(uint8_t *exe, uint32_t exesz, uint8_t *wwsect, struct cli_exe_section *sects, uint16_t scount, uint32_t pe, int desc) {
  uint8_t *structs = wwsect + 0x2a1, *compd, *ccur, *unpd, *ucur, bc;
  uint32_t src, srcend, szd, bt, bits;
  int error=0, i;

  cli_dbgmsg("in wwunpack\n");
  while (1) {
    if (!CLI_ISCONTAINED(wwsect, sects[scount].rsz, structs, 17)) {
      cli_dbgmsg("WWPack: Array of structs out of section\n");
      break;
    }
    src = sects[scount].rva - cli_readint32(structs); /* src delta / dst delta - not used / dwords / end of src */
    structs+=8;
    szd = cli_readint32(structs) * 4;
    structs+=4;
    srcend = cli_readint32(structs);
    structs+=4;

    unpd = ucur = exe+src+srcend+4-szd;
    if (!szd || !CLI_ISCONTAINED(exe, exesz, unpd, szd)) {
      cli_dbgmsg("WWPack: Compressed data out of file\n");
      break;
    }
    cli_dbgmsg("WWP: src: %x, szd: %x, srcend: %x - %x\n", src, szd, srcend, srcend+4-szd);
    if (!(compd = cli_malloc(szd))) {
        cli_dbgmsg("WWPack: Unable to allocate memory for compd\n");
        break;
    }
    memcpy(compd, unpd, szd);
    memset(unpd, -1, szd); /*FIXME*/
    ccur=compd;

    RESEED;
    while(!error) {
      uint32_t backbytes, backsize;
      uint8_t saved;

      BIT;
      if (!bits) { /* BYTE copy */
	if(ccur-compd>=szd || !CLI_ISCONTAINED(exe, exesz, ucur, 1))
	  error=1;
	else
	  *ucur++=*ccur++;
	continue;
      }

      BITS(2);
      if(bits==3) { /* WORD backcopy */
	uint8_t shifted, subbed = 31;
	BITS(2);
	shifted = bits + 5;
	if(bits>=2) {
	  shifted++;
	  subbed += 0x80;
	}
	backbytes = (1<<shifted)-subbed; /* 1h, 21h, 61h, 161h */
	BITS(shifted); /* 5, 6, 8, 9 */
	if(error || bits == 0x1ff) break;
	backbytes+=bits;
	if(!CLI_ISCONTAINED(exe, exesz, ucur, 2) || !CLI_ISCONTAINED(exe, exesz, ucur-backbytes, 2)) {
	  error=1;
	} else {
	  ucur[0]=*(ucur-backbytes);
	  ucur[1]=*(ucur-backbytes+1);
	  ucur+=2;
	}
	continue;
      }

      /* BLOCK backcopy */
      saved = bits; /* cmp al, 1 / pushf */

      BITS(3);
      if (bits<6) {
	backbytes = bits;
	switch(bits) {
	case 4: /* 10,11 */
	  backbytes++;
	case 3: /* 8,9 */
	  BIT;
	  backbytes+=bits;
	case 0:	case 1:	case 2: /* 5,6,7 */
	  backbytes+=5;
	  break;
	case 5: /* 12 */
	  backbytes=12;
	  break;
	}
	BITS(backbytes);
	bits+=(1<<backbytes)-31;
      } else if(bits==6) {
	BITS(0x0e);
	bits+=0x1fe1;
      } else {
	BITS(0x0f);
	bits+=0x5fe1;
      }

      backbytes = bits;

      /* popf / jb */
      if (!saved) {
	BIT;
	if(!bits) {
	  BIT;
	  bits+=5;
	} else {
	  BITS(3);
	  if(bits) {
	    bits+=6;
	  } else {
	    BITS(4);
	    if(bits) {
	      bits+=13;
	    } else {
	      uint8_t cnt = 4;
	      uint16_t shifted = 0x0d;

	      do {
		if(cnt==7) { cnt = 0x0e; shifted = 0; break; }
		shifted=((shifted+2)<<1)-1;
		BIT;
		cnt++;
	      } while(!bits);
	      BITS(cnt);
	      bits+=shifted;
	    }
	  }
	}
	backsize = bits;
      } else {
	backsize = saved+2;
      }

      if(!CLI_ISCONTAINED(exe, exesz, ucur, backsize) || !CLI_ISCONTAINED(exe, exesz, ucur-backbytes, backsize)) error=1;
      else while(backsize--) {
	*ucur=*(ucur-backbytes);
	ucur++;
      }
    }
    free(compd);
    if(error) {
      cli_dbgmsg("WWPack: decompression error\n");
      break;
    }
    if (error || !*structs++) break;
  }

  if(!error) {
    if (pe+6 > exesz || pe+7 > exesz || pe+0x28 > exesz ||
		pe+0x50 > exesz || pe+0x14 > exesz)
	return CL_EFORMAT;
    exe[pe+6]=(uint8_t)scount;
    exe[pe+7]=(uint8_t)(scount>>8);
    if (!CLI_ISCONTAINED(wwsect, sects[scount].rsz, wwsect+0x295, 4) ||
        !CLI_ISCONTAINED(wwsect, sects[scount].rsz, wwsect+0x295+sects[scount].rva, 4) ||
        !CLI_ISCONTAINED(wwsect, sects[scount].rsz, wwsect+0x295+sects[scount].rva+0x299, 4)) {
        cli_dbgmsg("WWPack: unpack memory address out of bounds.\n");
        return CL_EFORMAT;
    }
    cli_writeint32(&exe[pe+0x28], cli_readint32(wwsect+0x295)+sects[scount].rva+0x299);
    cli_writeint32(&exe[pe+0x50], cli_readint32(&exe[pe+0x50])-sects[scount].vsz);

    structs = &exe[(0xffff&cli_readint32(&exe[pe+0x14]))+pe+0x18];
    for(i=0 ; i<scount ; i++) {
	  if (!CLI_ISCONTAINED(exe, exesz, structs, 0x28)) {
	    cli_dbgmsg("WWPack: structs pointer out of bounds\n");
	    return CL_EFORMAT;
	  }

      cli_writeint32(structs+8, sects[i].vsz);
      cli_writeint32(structs+12, sects[i].rva);
      cli_writeint32(structs+16, sects[i].vsz);
      cli_writeint32(structs+20, sects[i].rva);
      structs+=0x28;
    }
	if (!CLI_ISCONTAINED(exe, exesz, structs, 0x28)) {
	  cli_dbgmsg("WWPack: structs pointer out of bounds\n");
	  return CL_EFORMAT;
	}

    memset(structs, 0, 0x28);
    error = (uint32_t)cli_writen(desc, exe, exesz)!=exesz;
  }
  return error;
}


MagickExport MagickBooleanType IsOptionMember(const char *option,
  const char *options)
{
  char
    **option_list,
    *string;

  int
    number_options;

  MagickBooleanType
    member;

  register ssize_t
    i;

  /*
    Is option a member of the options list?
  */
  if (options == (const char *) NULL)
    return(MagickFalse);
  string=ConstantString(options);
  (void) SubstituteString(&string,","," ");
  option_list=StringToArgv(string,&number_options);
  string=DestroyString(string);
  if (option_list == (char **) NULL)
    return(MagickFalse);
  member=MagickFalse;
  for (i=1; i < (ssize_t) number_options; i++)
  {
    if ((*option_list[i] == '!') &&
        (LocaleCompare(option,option_list[i]+1) == 0))
      break;
    if (GlobExpression(option,option_list[i],MagickTrue) != MagickFalse)
      {
        member=MagickTrue;
        break;
      }
    option_list[i]=DestroyString(option_list[i]);
  }
  for ( ; i < (ssize_t) number_options; i++)
    option_list[i]=DestroyString(option_list[i]);
  option_list=(char **) RelinquishMagickMemory(option_list);
  return(member);
}

Memory leak in the IsOptionMember function in MagickCore/option.c in ImageMagick before 6.9.2-2, as used in ODR-PadEnc and other products, allows attackers to trigger memory consumption.


MagickExport MagickBooleanType IsOptionMember(const char *option,
  const char *options)
{
  char
    **option_list,
    *string;

  int
    number_options;

  MagickBooleanType
    member;

  register ssize_t
    i;

  /*
    Is option a member of the options list?
  */
  if (options == (const char *) NULL)
    return(MagickFalse);
  string=ConstantString(options);
  (void) SubstituteString(&string,","," ");
  option_list=StringToArgv(string,&number_options);
  string=DestroyString(string);
  if (option_list == (char **) NULL)
    return(MagickFalse);
  member=MagickFalse;
  option_list[0]=DestroyString(option_list[0]);
  for (i=1; i < (ssize_t) number_options; i++)
  {
    if ((*option_list[i] == '!') &&
        (LocaleCompare(option,option_list[i]+1) == 0))
      break;
    if (GlobExpression(option,option_list[i],MagickTrue) != MagickFalse)
      {
        member=MagickTrue;
        break;
      }
    option_list[i]=DestroyString(option_list[i]);
  }
  for ( ; i < (ssize_t) number_options; i++)
    option_list[i]=DestroyString(option_list[i]);
  option_list=(char **) RelinquishMagickMemory(option_list);
  return(member);
}


ipv6: do not free rt if FIB_LOOKUP_NOREF is set on suppress rule

Commit 7d9e5f422150 removed references from certain dsts, but accounting
for this never translated down into the fib6 suppression code. This bug
was triggered by WireGuard users who use wg-quick(8), which uses the
"suppress-prefix" directive to ip-rule(8) for routing all of their
internet traffic without routing loops. The test case added here
causes the reference underflow by causing packets to evaluate a suppress
rule.

Fixes: 7d9e5f422150 ("ipv6: convert major tx path to use RT6_LOOKUP_F_DST_NOREF")
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Acked-by: Wei Wang <weiwan@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

static bool fib6_rule_suppress(struct fib_rule *rule, struct fib_lookup_arg *arg)
{
	struct fib6_result *res = arg->result;
	struct rt6_info *rt = res->rt6;
	struct net_device *dev = NULL;

	if (!rt)
		return false;

	if (rt->rt6i_idev)
		dev = rt->rt6i_idev->dev;

	/* do not accept result if the route does
	 * not meet the required prefix length
	 */
	if (rt->rt6i_dst.plen <= rule->suppress_prefixlen)
		goto suppress_route;

	/* do not accept result if the route uses a device
	 * belonging to a forbidden interface group
	 */
	if (rule->suppress_ifgroup != -1 && dev && dev->group == rule->suppress_ifgroup)
		goto suppress_route;

	return false;

suppress_route:
	ip6_rt_put(rt);
	return true;
}

Rejected reason: DO NOT USE THIS CANDIDATE NUMBER. ConsultIDs: CVE-2019-18198. Reason: This candidate is a reservation duplicate of CVE-2019-18198. Notes: All CVE users should reference CVE-2019-18198 instead of this candidate. All references and descriptions in this candidate have been removed to prevent accidental usage


static bool fib6_rule_suppress(struct fib_rule *rule, struct fib_lookup_arg *arg)
{
	struct fib6_result *res = arg->result;
	struct rt6_info *rt = res->rt6;
	struct net_device *dev = NULL;

	if (!rt)
		return false;

	if (rt->rt6i_idev)
		dev = rt->rt6i_idev->dev;

	/* do not accept result if the route does
	 * not meet the required prefix length
	 */
	if (rt->rt6i_dst.plen <= rule->suppress_prefixlen)
		goto suppress_route;

	/* do not accept result if the route uses a device
	 * belonging to a forbidden interface group
	 */
	if (rule->suppress_ifgroup != -1 && dev && dev->group == rule->suppress_ifgroup)
		goto suppress_route;

	return false;

suppress_route:
	if (!(arg->flags & FIB_LOOKUP_NOREF))
		ip6_rt_put(rt);
	return true;
}


Fix heap-buffer-overflow in color_esycc_to_rgb (#748)

When all components do not have the same dx/dy, components buffer are
read beyond their end.
Do not convert in this case.

Update uclouvain/openjpeg#725

void color_esycc_to_rgb(opj_image_t *image)
{
	int y, cb, cr, sign1, sign2, val;
	unsigned int w, h, max, i;
	int flip_value = (1 << (image->comps[0].prec-1));
	int max_value = (1 << image->comps[0].prec) - 1;

	if(image->numcomps < 3) return;

	w = image->comps[0].w;
	h = image->comps[0].h;

	sign1 = (int)image->comps[1].sgnd;
	sign2 = (int)image->comps[2].sgnd;

	max = w * h;

	for(i = 0; i < max; ++i)
	{

		y = image->comps[0].data[i]; cb = image->comps[1].data[i]; cr = image->comps[2].data[i];

		if( !sign1) cb -= flip_value;
		if( !sign2) cr -= flip_value;

		val = (int)
		((float)y - (float)0.0000368 * (float)cb
		 + (float)1.40199 * (float)cr + (float)0.5);

		if(val > max_value) val = max_value; else if(val < 0) val = 0;
		image->comps[0].data[i] = val;

		val = (int)
		((float)1.0003 * (float)y - (float)0.344125 * (float)cb
		 - (float)0.7141128 * (float)cr + (float)0.5);

		if(val > max_value) val = max_value; else if(val < 0) val = 0;
		image->comps[1].data[i] = val;

		val = (int)
		((float)0.999823 * (float)y + (float)1.77204 * (float)cb
		 - (float)0.000008 *(float)cr + (float)0.5);

		if(val > max_value) val = max_value; else if(val < 0) val = 0;
		image->comps[2].data[i] = val;
	}
	image->color_space = OPJ_CLRSPC_SRGB;

}/* color_esycc_to_rgb() */

The color_esycc_to_rgb function in bin/common/color.c in OpenJPEG before 2.1.1 allows attackers to cause a denial of service (memory corruption) via a crafted jpeg 2000 file.


Fix Heap Buffer Overflow in function color_cmyk_to_rgb

Fix uclouvain/openjpeg#774

void color_esycc_to_rgb(opj_image_t *image)
{
	int y, cb, cr, sign1, sign2, val;
	unsigned int w, h, max, i;
	int flip_value = (1 << (image->comps[0].prec-1));
	int max_value = (1 << image->comps[0].prec) - 1;

	if (
		    (image->numcomps < 3)
		 || (image->comps[0].dx != image->comps[1].dx) || (image->comps[0].dx != image->comps[2].dx)
		 || (image->comps[0].dy != image->comps[1].dy) || (image->comps[0].dy != image->comps[2].dy)
	   ) {
		fprintf(stderr,"%s:%d:color_esycc_to_rgb\n\tCAN NOT CONVERT\n", __FILE__,__LINE__);
		return;
	}

	w = image->comps[0].w;
	h = image->comps[0].h;

	sign1 = (int)image->comps[1].sgnd;
	sign2 = (int)image->comps[2].sgnd;

	max = w * h;

	for(i = 0; i < max; ++i)
	{

		y = image->comps[0].data[i]; cb = image->comps[1].data[i]; cr = image->comps[2].data[i];

		if( !sign1) cb -= flip_value;
		if( !sign2) cr -= flip_value;

		val = (int)
		((float)y - (float)0.0000368 * (float)cb
		 + (float)1.40199 * (float)cr + (float)0.5);

		if(val > max_value) val = max_value; else if(val < 0) val = 0;
		image->comps[0].data[i] = val;

		val = (int)
		((float)1.0003 * (float)y - (float)0.344125 * (float)cb
		 - (float)0.7141128 * (float)cr + (float)0.5);

		if(val > max_value) val = max_value; else if(val < 0) val = 0;
		image->comps[1].data[i] = val;

		val = (int)
		((float)0.999823 * (float)y + (float)1.77204 * (float)cb
		 - (float)0.000008 *(float)cr + (float)0.5);

		if(val > max_value) val = max_value; else if(val < 0) val = 0;
		image->comps[2].data[i] = val;
	}
	image->color_space = OPJ_CLRSPC_SRGB;

}/* color_esycc_to_rgb() */

Heap-based buffer overflow in the color_cmyk_to_rgb in common/color.c in OpenJPEG before 2.1.1 allows remote attackers to cause a denial of service (crash) via a crafted .j2k file.


Fix integer overflow in MallocFrameBuffer()

Promote integers to uint64_t to avoid integer overflow issue during
frame buffer allocation for very large screen sizes

static rfbBool MallocFrameBuffer(rfbClient* client) {
  if(client->frameBuffer)
    free(client->frameBuffer);
  client->frameBuffer=malloc(client->width*client->height*client->format.bitsPerPixel/8);
  return client->frameBuffer?TRUE:FALSE;
}

Integer overflow in the MallocFrameBuffer function in vncviewer.c in LibVNCServer 0.9.9 and earlier allows remote VNC servers to cause a denial of service (crash) and possibly execute arbitrary code via an advertisement for a large screen size, which triggers a heap-based buffer overflow.


static rfbBool MallocFrameBuffer(rfbClient* client) {
uint64_t allocSize;

  if(client->frameBuffer)
    free(client->frameBuffer);

  /* SECURITY: promote 'width' into uint64_t so that the multiplication does not overflow
     'width' and 'height' are 16-bit integers per RFB protocol design
     SIZE_MAX is the maximum value that can fit into size_t
  */
  allocSize = (uint64_t)client->width * client->height * client->format.bitsPerPixel/8;

  if (allocSize >= SIZE_MAX) {
    rfbClientErr("CRITICAL: cannot allocate frameBuffer, requested size is too large\n");
    return FALSE;
  }

  client->frameBuffer=malloc( (size_t)allocSize );

  if (client->frameBuffer == NULL)
    rfbClientErr("CRITICAL: frameBuffer allocation failed, requested size too large or not enough memory?\n");

  return client->frameBuffer?TRUE:FALSE;
}


Reduce dynamic allocations by using arrays for all small arrays.

fribidi_get_par_embedding_levels_ex (
  /* input */
  const FriBidiCharType *bidi_types,
  const FriBidiBracketType *bracket_types,
  const FriBidiStrIndex len,
  /* input and output */
  FriBidiParType *pbase_dir,
  /* output */
  FriBidiLevel *embedding_levels
)
{
  FriBidiLevel base_level, *base_level_per_iso_level = NULL, max_level = 0;
  FriBidiParType base_dir;
  FriBidiRun *main_run_list = NULL, *explicits_list = NULL, *pp;
  fribidi_boolean status = false;
  int max_iso_level = 0;

  if UNLIKELY
    (!len)
    {
      status = true;
      goto out;
    }

  DBG ("in fribidi_get_par_embedding_levels");

  fribidi_assert (bidi_types);
  fribidi_assert (pbase_dir);
  fribidi_assert (embedding_levels);

  /* Determinate character types */
  {
    /* Get run-length encoded character types */
    main_run_list = run_list_encode_bidi_types (bidi_types, bracket_types, len);
    if UNLIKELY
      (!main_run_list) goto out;
  }

  /* Find base level */
  /* If no strong base_dir was found, resort to the weak direction
     that was passed on input. */
  base_level = FRIBIDI_DIR_TO_LEVEL (*pbase_dir);
  if (!FRIBIDI_IS_STRONG (*pbase_dir))
    /* P2. P3. Search for first strong character and use its direction as
       base direction */
    {
      int valid_isolate_count = 0;
      for_run_list (pp, main_run_list)
        {
          if (RL_TYPE(pp) == FRIBIDI_TYPE_PDI)
            {
              /* Ignore if there is no matching isolate */
              if (valid_isolate_count>0)
                valid_isolate_count--;
            }
          else if (FRIBIDI_IS_ISOLATE(RL_TYPE(pp)))
            valid_isolate_count++;
          else if (valid_isolate_count==0 && FRIBIDI_IS_LETTER (RL_TYPE (pp)))
            {
              base_level = FRIBIDI_DIR_TO_LEVEL (RL_TYPE (pp));
              *pbase_dir = FRIBIDI_LEVEL_TO_DIR (base_level);
              break;
            }
        }
    }
  base_dir = FRIBIDI_LEVEL_TO_DIR (base_level);
  DBG2 ("  base level : %c", fribidi_char_from_level (base_level));
  DBG2 ("  base dir   : %s", fribidi_get_bidi_type_name (base_dir));

  base_level_per_iso_level = fribidi_malloc(sizeof(base_level_per_iso_level[0]) *
                                            FRIBIDI_BIDI_MAX_EXPLICIT_LEVEL);
  base_level_per_iso_level[0] = base_level;

# if DEBUG
  if UNLIKELY
    (fribidi_debug_status ())
    {
      print_types_re (main_run_list);
    }
# endif	/* DEBUG */

  /* Explicit Levels and Directions */
  DBG ("explicit levels and directions");
  {
    FriBidiLevel level, new_level = 0;
    int isolate_level = 0;
    FriBidiCharType override, new_override;
    FriBidiStrIndex i;
    int stack_size, over_pushed, first_interval;
    int valid_isolate_count = 0;
    int isolate_overflow = 0;
    int isolate = 0; /* The isolate status flag */
    struct
    {
      FriBidiCharType override;	/* only LTR, RTL and ON are valid */
      FriBidiLevel level;
      int isolate;
      int isolate_level;
    } *status_stack;
    FriBidiRun temp_link;
    FriBidiRun **run_per_isolate_level; /* Connect the isolate levels */

    run_per_isolate_level = fribidi_malloc(sizeof(run_per_isolate_level[0])
                                           * FRIBIDI_BIDI_MAX_RESOLVED_LEVELS);
    memset(run_per_isolate_level, 0, sizeof(run_per_isolate_level[0])
           * FRIBIDI_BIDI_MAX_RESOLVED_LEVELS);

/* explicits_list is a list like main_run_list, that holds the explicit
   codes that are removed from main_run_list, to reinsert them later by
   calling the shadow_run_list.
*/
    explicits_list = new_run_list ();
    if UNLIKELY
      (!explicits_list) goto out;

    /* X1. Begin by setting the current embedding level to the paragraph
       embedding level. Set the directional override status to neutral,
       and directional isolate status to false.

       Process each character iteratively, applying rules X2 through X8.
       Only embedding levels from 0 to 123 are valid in this phase. */

    level = base_level;
    override = FRIBIDI_TYPE_ON;
    /* stack */
    stack_size = 0;
    over_pushed = 0;
    first_interval = 0;
    valid_isolate_count = 0;
    isolate_overflow = 0;
    status_stack = fribidi_malloc (sizeof (status_stack[0]) *
				   FRIBIDI_BIDI_MAX_RESOLVED_LEVELS);

    for_run_list (pp, main_run_list)
    {
      FriBidiCharType this_type = RL_TYPE (pp);
      RL_ISOLATE_LEVEL (pp) = isolate_level;

      if (FRIBIDI_IS_EXPLICIT_OR_BN (this_type))
	{
	  if (FRIBIDI_IS_STRONG (this_type))
	    {			/* LRE, RLE, LRO, RLO */
	      /* 1. Explicit Embeddings */
	      /*   X2. With each RLE, compute the least greater odd
	         embedding level. */
	      /*   X3. With each LRE, compute the least greater even
	         embedding level. */
	      /* 2. Explicit Overrides */
	      /*   X4. With each RLO, compute the least greater odd
	         embedding level. */
	      /*   X5. With each LRO, compute the least greater even
	         embedding level. */
	      new_override = FRIBIDI_EXPLICIT_TO_OVERRIDE_DIR (this_type);
	      for (i = RL_LEN (pp); i; i--)
		{
		  new_level =
		    ((level + FRIBIDI_DIR_TO_LEVEL (this_type) + 2) & ~1) -
		    FRIBIDI_DIR_TO_LEVEL (this_type);
                  isolate = 0;
		  PUSH_STATUS;
		}
	    }
	  else if (this_type == FRIBIDI_TYPE_PDF)
	    {
	      /* 3. Terminating Embeddings and overrides */
	      /*   X7. With each PDF, determine the matching embedding or
	         override code. */
              for (i = RL_LEN (pp); i; i--)
                {
                  if (stack_size && status_stack[stack_size-1].isolate != 0)
                    break;
                  POP_STATUS;
                }
	    }

	  /* X9. Remove all RLE, LRE, RLO, LRO, PDF, and BN codes. */
	  /* Remove element and add it to explicits_list */
	  RL_LEVEL (pp) = FRIBIDI_SENTINEL;
	  temp_link.next = pp->next;
	  move_node_before (pp, explicits_list);
	  pp = &temp_link;
	}
      else if (this_type == FRIBIDI_TYPE_PDI)
        /* X6a. pop the direction of the stack */
        {
          for (i = RL_LEN (pp); i; i--)
            {
              if (isolate_overflow > 0)
                {
                  isolate_overflow--;
                  RL_LEVEL (pp) = level;
                }

              else if (valid_isolate_count > 0)
                {
                  /* Pop away all LRE,RLE,LRO, RLO levels
                     from the stack, as these are implicitly
                     terminated by the PDI */
                  while (stack_size && !status_stack[stack_size-1].isolate)
                    POP_STATUS;
                  over_pushed = 0; /* The PDI resets the overpushed! */
                  POP_STATUS;
                  isolate_level-- ;
                  valid_isolate_count--;
                  RL_LEVEL (pp) = level;
                  RL_ISOLATE_LEVEL (pp) = isolate_level;
                }
              else
                {
                  /* Ignore isolated PDI's by turning them into ON's */
                  RL_TYPE (pp) = FRIBIDI_TYPE_ON;
                  RL_LEVEL (pp) = level;
                }
            }
        }
      else if (FRIBIDI_IS_ISOLATE(this_type))
        {
          /* TBD support RL_LEN > 1 */
          new_override = FRIBIDI_TYPE_ON;
          isolate = 1;
          if (this_type == FRIBIDI_TYPE_LRI)
            new_level = level + 2 - (level%2);
          else if (this_type == FRIBIDI_TYPE_RLI)
            new_level = level + 1 + (level%2);
          else if (this_type == FRIBIDI_TYPE_FSI)
            {
              /* Search for a local strong character until we
                 meet the corresponding PDI or the end of the
                 paragraph */
              FriBidiRun *fsi_pp;
              int isolate_count = 0;
              int fsi_base_level = 0;
              for_run_list (fsi_pp, pp)
                {
                  if (RL_TYPE(fsi_pp) == FRIBIDI_TYPE_PDI)
                    {
                      isolate_count--;
                      if (valid_isolate_count < 0)
                        break;
                    }
                  else if (FRIBIDI_IS_ISOLATE(RL_TYPE(fsi_pp)))
                    isolate_count++;
                  else if (isolate_count==0 && FRIBIDI_IS_LETTER (RL_TYPE (fsi_pp)))
                    {
                      fsi_base_level = FRIBIDI_DIR_TO_LEVEL (RL_TYPE (fsi_pp));
                      break;
                    }
                }

              /* Same behavior like RLI and LRI above */
              if (FRIBIDI_LEVEL_IS_RTL (fsi_base_level))
                new_level = level + 1 + (level%2);
              else
                new_level = level + 2 - (level%2);
            }

	  RL_LEVEL (pp) = level;
          RL_ISOLATE_LEVEL (pp) = isolate_level++;
          base_level_per_iso_level[isolate_level] = new_level;

	  if (!FRIBIDI_IS_NEUTRAL (override))
	    RL_TYPE (pp) = override;

          if (new_level <= FRIBIDI_BIDI_MAX_EXPLICIT_LEVEL)
            {
              valid_isolate_count++;
              PUSH_STATUS;
              level = new_level;
            }
          else
            isolate_overflow += 1;
        }
      else if (this_type == FRIBIDI_TYPE_BS)
	{
	  /* X8. All explicit directional embeddings and overrides are
	     completely terminated at the end of each paragraph. Paragraph
	     separators are not included in the embedding. */
	  break;
	}
      else
	{
	  /* X6. For all types besides RLE, LRE, RLO, LRO, and PDF:
	     a. Set the level of the current character to the current
	     embedding level.
	     b. Whenever the directional override status is not neutral,
	     reset the current character type to the directional override
	     status. */
	  RL_LEVEL (pp) = level;
	  if (!FRIBIDI_IS_NEUTRAL (override))
	    RL_TYPE (pp) = override;
	}
    }

    /* Build the isolate_level connections */
    for_run_list (pp, main_run_list)
    {
      int isolate_level = RL_ISOLATE_LEVEL (pp);
      if (run_per_isolate_level[isolate_level])
        {
          run_per_isolate_level[isolate_level]->next_isolate = pp;
          pp->prev_isolate = run_per_isolate_level[isolate_level];
        }
      run_per_isolate_level[isolate_level] = pp;
    }

    /* Implementing X8. It has no effect on a single paragraph! */
    level = base_level;
    override = FRIBIDI_TYPE_ON;
    stack_size = 0;
    over_pushed = 0;

    fribidi_free (status_stack);
    fribidi_free (run_per_isolate_level);
  }
  /* X10. The remaining rules are applied to each run of characters at the
     same level. For each run, determine the start-of-level-run (sor) and
     end-of-level-run (eor) type, either L or R. This depends on the
     higher of the two levels on either side of the boundary (at the start
     or end of the paragraph, the level of the 'other' run is the base
     embedding level). If the higher level is odd, the type is R, otherwise
     it is L. */
  /* Resolving Implicit Levels can be done out of X10 loop, so only change
     of Resolving Weak Types and Resolving Neutral Types is needed. */

  compact_list (main_run_list);

# if DEBUG
  if UNLIKELY
    (fribidi_debug_status ())
    {
      print_types_re (main_run_list);
      print_bidi_string (bidi_types, len);
      print_resolved_levels (main_run_list);
      print_resolved_types (main_run_list);
    }
# endif	/* DEBUG */

  /* 4. Resolving weak types. Also calculate the maximum isolate level */
  max_iso_level = 0;
  DBG ("resolving weak types");
  {
    int *last_strong_stack;
    FriBidiCharType prev_type_orig;
    fribidi_boolean w4;

    last_strong_stack = fribidi_malloc (sizeof (int)
                                        * FRIBIDI_BIDI_MAX_RESOLVED_LEVELS);
    last_strong_stack[0] = base_dir;

    for_run_list (pp, main_run_list)
    {
      register FriBidiCharType prev_type, this_type, next_type;
      FriBidiRun *ppp_prev, *ppp_next;
      int iso_level;

      ppp_prev = get_adjacent_run(pp, false, false);
      ppp_next = get_adjacent_run(pp, true, false);

      this_type = RL_TYPE (pp);
      iso_level = RL_ISOLATE_LEVEL(pp);

      if (iso_level > max_iso_level)
        max_iso_level = iso_level;

      if (RL_LEVEL(ppp_prev) == RL_LEVEL(pp))
        prev_type = RL_TYPE(ppp_prev);
      else
        prev_type = FRIBIDI_LEVEL_TO_DIR(MAX(RL_LEVEL(ppp_prev), RL_LEVEL(pp)));

      if (RL_LEVEL(ppp_next) == RL_LEVEL(pp))
        next_type = RL_TYPE(ppp_next);
      else
        next_type = FRIBIDI_LEVEL_TO_DIR(MAX(RL_LEVEL(ppp_next), RL_LEVEL(pp)));

      if (FRIBIDI_IS_STRONG (prev_type))
	last_strong_stack[iso_level] = prev_type;

      /* W1. NSM
         Examine each non-spacing mark (NSM) in the level run, and change the
         type of the NSM to the type of the previous character. If the NSM
         is at the start of the level run, it will get the type of sor. */
      /* Implementation note: it is important that if the previous character
         is not sor, then we should merge this run with the previous,
         because of rules like W5, that we assume all of a sequence of
         adjacent ETs are in one FriBidiRun. */
      if (this_type == FRIBIDI_TYPE_NSM)
	{
          /* New rule in Unicode 6.3 */
          if (FRIBIDI_IS_ISOLATE (RL_TYPE (pp->prev)))
              RL_TYPE(pp) = FRIBIDI_TYPE_ON;

	  if (RL_LEVEL (ppp_prev) == RL_LEVEL (pp))
            {
              if (ppp_prev == pp->prev)
                pp = merge_with_prev (pp);
            }
	  else
	    RL_TYPE (pp) = prev_type;

	  if (prev_type == next_type && RL_LEVEL (pp) == RL_LEVEL (pp->next))
	    {
              if (ppp_next == pp->next)
                pp = merge_with_prev (pp->next);
	    }
	  continue;		/* As we know the next condition cannot be true. */
	}

      /* W2: European numbers. */
      if (this_type == FRIBIDI_TYPE_EN && last_strong_stack[iso_level] == FRIBIDI_TYPE_AL)
	{
	  RL_TYPE (pp) = FRIBIDI_TYPE_AN;

	  /* Resolving dependency of loops for rules W1 and W2, so we
	     can merge them in one loop. */
	  if (next_type == FRIBIDI_TYPE_NSM)
	    RL_TYPE (ppp_next) = FRIBIDI_TYPE_AN;
	}
    }

    last_strong_stack[0] = base_dir;

    /* Resolving dependency of loops for rules W4 and W5, W5 may
       want to prevent W4 to take effect in the next turn, do this
       through "w4". */
    w4 = true;
    /* Resolving dependency of loops for rules W4 and W5 with W7,
       W7 may change an EN to L but it sets the prev_type_orig if needed,
       so W4 and W5 in next turn can still do their works. */
    prev_type_orig = FRIBIDI_TYPE_ON;

    /* Each isolate level has its own memory of the last strong character */
    for_run_list (pp, main_run_list)
    {
      register FriBidiCharType prev_type, this_type, next_type;
      int iso_level;
      FriBidiRun *ppp_prev, *ppp_next;

      this_type = RL_TYPE (pp);
      iso_level = RL_ISOLATE_LEVEL(pp);

      ppp_prev = get_adjacent_run(pp, false, false);
      ppp_next = get_adjacent_run(pp, true, false);

      if (RL_LEVEL(ppp_prev) == RL_LEVEL(pp))
        prev_type = RL_TYPE(ppp_prev);
      else
        prev_type = FRIBIDI_LEVEL_TO_DIR(MAX(RL_LEVEL(ppp_prev), RL_LEVEL(pp)));

      if (RL_LEVEL(ppp_next) == RL_LEVEL(pp))
        next_type = RL_TYPE(ppp_next);
      else
        next_type = FRIBIDI_LEVEL_TO_DIR(MAX(RL_LEVEL(ppp_next), RL_LEVEL(pp)));

      if (FRIBIDI_IS_STRONG (prev_type))
	last_strong_stack[iso_level] = prev_type;

      /* W2 ??? */

      /* W3: Change ALs to R. */
      if (this_type == FRIBIDI_TYPE_AL)
	{
	  RL_TYPE (pp) = FRIBIDI_TYPE_RTL;
	  w4 = true;
	  prev_type_orig = FRIBIDI_TYPE_ON;
	  continue;
	}

      /* W4. A single european separator changes to a european number.
         A single common separator between two numbers of the same type
         changes to that type. */
      if (w4
	  && RL_LEN (pp) == 1 && FRIBIDI_IS_ES_OR_CS (this_type)
	  && FRIBIDI_IS_NUMBER (prev_type_orig)
	  && prev_type_orig == next_type
	  && (prev_type_orig == FRIBIDI_TYPE_EN
	      || this_type == FRIBIDI_TYPE_CS))
	{
	  RL_TYPE (pp) = prev_type;
	  this_type = RL_TYPE (pp);
	}
      w4 = true;

      /* W5. A sequence of European terminators adjacent to European
         numbers changes to All European numbers. */
      if (this_type == FRIBIDI_TYPE_ET
	  && (prev_type_orig == FRIBIDI_TYPE_EN
	      || next_type == FRIBIDI_TYPE_EN))
	{
	  RL_TYPE (pp) = FRIBIDI_TYPE_EN;
	  w4 = false;
	  this_type = RL_TYPE (pp);
	}

      /* W6. Otherwise change separators and terminators to other neutral. */
      if (FRIBIDI_IS_NUMBER_SEPARATOR_OR_TERMINATOR (this_type))
	RL_TYPE (pp) = FRIBIDI_TYPE_ON;

      /* W7. Change european numbers to L. */
      if (this_type == FRIBIDI_TYPE_EN && last_strong_stack[iso_level] == FRIBIDI_TYPE_LTR)
	{
	  RL_TYPE (pp) = FRIBIDI_TYPE_LTR;
	  prev_type_orig = (RL_LEVEL (pp) == RL_LEVEL (pp->next) ?
			    FRIBIDI_TYPE_EN : FRIBIDI_TYPE_ON);
	}
      else
	prev_type_orig = PREV_TYPE_OR_SOR (pp->next);
    }

    fribidi_free (last_strong_stack);
  }

  compact_neutrals (main_run_list);

# if DEBUG
  if UNLIKELY
    (fribidi_debug_status ())
    {
      print_resolved_levels (main_run_list);
      print_resolved_types (main_run_list);
    }
# endif	/* DEBUG */

  /* 5. Resolving Neutral Types */

  DBG ("resolving neutral types - N0");
  {
    /*  BD16 - Build list of all pairs*/
    int num_iso_levels = max_iso_level + 1;
    FriBidiPairingNode *pairing_nodes = NULL;
    FriBidiRun ***bracket_stack = fribidi_malloc(sizeof(bracket_stack[0])
                                                 * num_iso_levels);
    int *bracket_stack_size = fribidi_malloc(sizeof(bracket_stack_size[0])
                                             * num_iso_levels);
    int last_level = RL_LEVEL(main_run_list);
    int last_iso_level = 0;

    memset(bracket_stack, 0, sizeof(bracket_stack[0])*num_iso_levels);
    memset(bracket_stack_size, 0, sizeof(bracket_stack_size[0])*num_iso_levels);

    /* Build the bd16 pair stack. */
    for_run_list (pp, main_run_list)
      {
        int level = RL_LEVEL(pp);
        int iso_level = RL_ISOLATE_LEVEL(pp);
        FriBidiBracketType brack_prop = RL_BRACKET_TYPE(pp);

        /* Interpret the isolating run sequence as such that they
           end at a change in the level, unless the iso_level has been
           raised. */
        if (level != last_level && last_iso_level == iso_level)
          bracket_stack_size[last_iso_level] = 0;

        if (!bracket_stack[iso_level])
          bracket_stack[iso_level] = fribidi_malloc (sizeof (bracket_stack[0])
                                                     * FRIBIDI_BIDI_MAX_NESTED_BRACKET_PAIRS);
        if (brack_prop!= FRIBIDI_NO_BRACKET)
          {
            if (FRIBIDI_IS_BRACKET_OPEN(brack_prop))
              {
                if (bracket_stack_size[iso_level]==FRIBIDI_BIDI_MAX_NESTED_BRACKET_PAIRS)
                  break;

                /* push onto the pair stack */
                bracket_stack[iso_level][bracket_stack_size[iso_level]++] = pp;
              }
            else
              {
                int stack_idx = bracket_stack_size[iso_level] - 1;
                while (stack_idx >= 0)
                  {
                    FriBidiBracketType se_brack_prop = RL_BRACKET_TYPE(bracket_stack[iso_level][stack_idx]);
                    if (FRIBIDI_BRACKET_ID(se_brack_prop) == FRIBIDI_BRACKET_ID(brack_prop))
                      {
                        bracket_stack_size[iso_level] = stack_idx;

                        pairing_nodes = pairing_nodes_push(pairing_nodes,
                                                           bracket_stack[iso_level][stack_idx],
                                                           pp);
                        break;
                    }
                    stack_idx--;
                  }
              }
          }
        last_level = level;
        last_iso_level = iso_level;
      }

    /* The list must now be sorted for the next algo to work! */
    sort_pairing_nodes(&pairing_nodes);

# if DEBUG
    if UNLIKELY
    (fribidi_debug_status ())
      {
        print_pairing_nodes (pairing_nodes);
      }
# endif	/* DEBUG */

    /* Start the N0 */
    {
      FriBidiPairingNode *ppairs = pairing_nodes;
      while (ppairs)
        {
          int iso_level = ppairs->open->isolate_level;
          int embedding_level = base_level_per_iso_level[iso_level];

          /* Find matching strong. */
          fribidi_boolean found = false;
          FriBidiRun *ppn;
          for (ppn = ppairs->open; ppn!= ppairs->close; ppn = ppn->next)
            {
              FriBidiCharType this_type = RL_TYPE_AN_EN_AS_RTL(ppn);

              /* Calculate level like in resolve implicit levels below to prevent
                 embedded levels not to match the base_level */
              int this_level = RL_LEVEL (ppn) +
                (FRIBIDI_LEVEL_IS_RTL (RL_LEVEL(ppn)) ^ FRIBIDI_DIR_TO_LEVEL (this_type));

              /* N0b */
              if (FRIBIDI_IS_STRONG (this_type) && this_level == embedding_level)
                {
                  RL_TYPE(ppairs->open) = RL_TYPE(ppairs->close) = this_level%2 ? FRIBIDI_TYPE_RTL : FRIBIDI_TYPE_LTR;
                  found = true;
                  break;
                }
            }

          /* N0c */
          /* Search for any strong type preceding and within the bracket pair */
          if (!found)
            {
              /* Search for a preceding strong */
              int prec_strong_level = embedding_level; /* TBDov! Extract from Isolate level in effect */
              int iso_level = RL_ISOLATE_LEVEL(ppairs->open);
              for (ppn = ppairs->open->prev; ppn->type != FRIBIDI_TYPE_SENTINEL; ppn=ppn->prev)
                {
                  FriBidiCharType this_type = RL_TYPE_AN_EN_AS_RTL(ppn);
                  if (FRIBIDI_IS_STRONG (this_type) && RL_ISOLATE_LEVEL(ppn) == iso_level)
                    {
                      prec_strong_level = RL_LEVEL (ppn) +
                        (FRIBIDI_LEVEL_IS_RTL (RL_LEVEL(ppn)) ^ FRIBIDI_DIR_TO_LEVEL (this_type));

                      break;
                    }
                }

              for (ppn = ppairs->open; ppn!= ppairs->close; ppn = ppn->next)
                {
                  FriBidiCharType this_type = RL_TYPE_AN_EN_AS_RTL(ppn);
                  if (FRIBIDI_IS_STRONG (this_type) && RL_ISOLATE_LEVEL(ppn) == iso_level)
                    {
                      /* By constraint this is opposite the embedding direction,
                         since we did not match the N0b rule. We must now
                         compare with the preceding strong to establish whether
                         to apply N0c1 (opposite) or N0c2 embedding */
                      RL_TYPE(ppairs->open) = RL_TYPE(ppairs->close) = prec_strong_level % 2 ? FRIBIDI_TYPE_RTL : FRIBIDI_TYPE_LTR;
                      RL_LEVEL(ppairs->open) = RL_LEVEL(ppairs->close) = prec_strong_level;
                      found = true;
                      break;
                    }
                }
            }

          ppairs = ppairs->next;
        }

      free_pairing_nodes(pairing_nodes);
      {
        int i;
        for (i=0; i<num_iso_levels; i++)
          fribidi_free(bracket_stack[i]);
      }
      fribidi_free(bracket_stack);
      fribidi_free(bracket_stack_size);

      /* Remove the bracket property and re-compact */
      {
        const FriBidiBracketType NoBracket = FRIBIDI_NO_BRACKET;
        for_run_list (pp, main_run_list)
          pp->bracket_type = NoBracket;
        compact_list (main_run_list);
      }
    }

# if DEBUG
  if UNLIKELY
    (fribidi_debug_status ())
    {
      print_resolved_levels (main_run_list);
      print_resolved_types (main_run_list);
    }
# endif	/* DEBUG */
  }

  DBG ("resolving neutral types - N1+N2");
  {
    for_run_list (pp, main_run_list)
    {
      FriBidiCharType prev_type, this_type, next_type;
      FriBidiRun *ppp_prev, *ppp_next;

      ppp_prev = get_adjacent_run(pp, false, false);
      ppp_next = get_adjacent_run(pp, true, false);

      /* "European and Arabic numbers are treated as though they were R"
         FRIBIDI_CHANGE_NUMBER_TO_RTL does this. */
      this_type = FRIBIDI_CHANGE_NUMBER_TO_RTL (RL_TYPE (pp));

      if (RL_LEVEL(ppp_prev) == RL_LEVEL(pp))
        prev_type = FRIBIDI_CHANGE_NUMBER_TO_RTL (RL_TYPE(ppp_prev));
      else
        prev_type = FRIBIDI_LEVEL_TO_DIR(MAX(RL_LEVEL(ppp_prev), RL_LEVEL(pp)));

      if (RL_LEVEL(ppp_next) == RL_LEVEL(pp))
        next_type = FRIBIDI_CHANGE_NUMBER_TO_RTL (RL_TYPE(ppp_next));
      else
        next_type = FRIBIDI_LEVEL_TO_DIR(MAX(RL_LEVEL(ppp_next), RL_LEVEL(pp)));

      if (FRIBIDI_IS_NEUTRAL (this_type))
	RL_TYPE (pp) = (prev_type == next_type) ?
	  /* N1. */ prev_type :
	  /* N2. */ FRIBIDI_EMBEDDING_DIRECTION (pp);
    }
  }

  compact_list (main_run_list);

# if DEBUG
  if UNLIKELY
    (fribidi_debug_status ())
    {
      print_resolved_levels (main_run_list);
      print_resolved_types (main_run_list);
    }
# endif	/* DEBUG */

  /* 6. Resolving implicit levels */
  DBG ("resolving implicit levels");
  {
    max_level = base_level;

    for_run_list (pp, main_run_list)
    {
      FriBidiCharType this_type;
      int level;

      this_type = RL_TYPE (pp);
      level = RL_LEVEL (pp);

      /* I1. Even */
      /* I2. Odd */
      if (FRIBIDI_IS_NUMBER (this_type))
	RL_LEVEL (pp) = (level + 2) & ~1;
      else
	RL_LEVEL (pp) =
	  level +
	  (FRIBIDI_LEVEL_IS_RTL (level) ^ FRIBIDI_DIR_TO_LEVEL (this_type));

      if (RL_LEVEL (pp) > max_level)
	max_level = RL_LEVEL (pp);
    }
  }

  compact_list (main_run_list);

# if DEBUG
  if UNLIKELY
    (fribidi_debug_status ())
    {
      print_bidi_string (bidi_types, len);
      print_resolved_levels (main_run_list);
      print_resolved_types (main_run_list);
    }
# endif	/* DEBUG */

/* Reinsert the explicit codes & BN's that are already removed, from the
   explicits_list to main_run_list. */
  DBG ("reinserting explicit codes");
  if UNLIKELY
    (explicits_list->next != explicits_list)
    {
      register FriBidiRun *p;
      register fribidi_boolean stat =
	shadow_run_list (main_run_list, explicits_list, true);
      explicits_list = NULL;
      if UNLIKELY
	(!stat) goto out;

      /* Set level of inserted explicit chars to that of their previous
       * char, such that they do not affect reordering. */
      p = main_run_list->next;
      if (p != main_run_list && p->level == FRIBIDI_SENTINEL)
	p->level = base_level;
      for_run_list (p, main_run_list) if (p->level == FRIBIDI_SENTINEL)
	p->level = p->prev->level;
    }

# if DEBUG
  if UNLIKELY
    (fribidi_debug_status ())
    {
      print_types_re (main_run_list);
      print_resolved_levels (main_run_list);
      print_resolved_types (main_run_list);
    }
# endif	/* DEBUG */

  DBG ("reset the embedding levels, 1, 2, 3.");
  {
    register int j, state, pos;
    register FriBidiCharType char_type;
    register FriBidiRun *p, *q, *list;

    /* L1. Reset the embedding levels of some chars:
       1. segment separators,
       2. paragraph separators,
       3. any sequence of whitespace characters preceding a segment
          separator or paragraph separator, and
       4. any sequence of whitespace characters and/or isolate formatting
          characters at the end of the line.
       ... (to be continued in fribidi_reorder_line()). */
    list = new_run_list ();
    if UNLIKELY
      (!list) goto out;
    q = list;
    state = 1;
    pos = len - 1;
    for (j = len - 1; j >= -1; j--)
      {
	/* close up the open link at the end */
	if (j >= 0)
	  char_type = bidi_types[j];
	else
	  char_type = FRIBIDI_TYPE_ON;
	if (!state && FRIBIDI_IS_SEPARATOR (char_type))
	  {
	    state = 1;
	    pos = j;
	  }
	else if (state &&
                 !(FRIBIDI_IS_EXPLICIT_OR_SEPARATOR_OR_BN_OR_WS(char_type)
                   || FRIBIDI_IS_ISOLATE(char_type)))
	  {
	    state = 0;
	    p = new_run ();
	    if UNLIKELY
	      (!p)
	      {
		free_run_list (list);
		goto out;
	      }
	    p->pos = j + 1;
	    p->len = pos - j;
	    p->type = base_dir;
	    p->level = base_level;
	    move_node_before (p, q);
	    q = p;
	  }
      }
    if UNLIKELY
      (!shadow_run_list (main_run_list, list, false)) goto out;
  }

# if DEBUG
  if UNLIKELY
    (fribidi_debug_status ())
    {
      print_types_re (main_run_list);
      print_resolved_levels (main_run_list);
      print_resolved_types (main_run_list);
    }
# endif	/* DEBUG */

  {
    FriBidiStrIndex pos = 0;
    for_run_list (pp, main_run_list)
    {
      register FriBidiStrIndex l;
      register FriBidiLevel level = pp->level;
      for (l = pp->len; l; l--)
	embedding_levels[pos++] = level;
    }
  }

  status = true;

out:
  DBG ("leaving fribidi_get_par_embedding_levels");

  if (main_run_list)
    free_run_list (main_run_list);
  if UNLIKELY
    (explicits_list) free_run_list (explicits_list);
  if (base_level_per_iso_level)
    fribidi_free (base_level_per_iso_level);

  return status ? max_level + 1 : 0;
}

A buffer overflow in the fribidi_get_par_embedding_levels_ex() function in lib/fribidi-bidi.c of GNU FriBidi through 1.0.7 allows an attacker to cause a denial of service or possibly execute arbitrary code by delivering crafted text content to a user, when this content is then rendered by an application that uses FriBidi for text layout calculations. Examples include any GNOME or GTK+ based application that uses Pango for text layout, as this internally uses FriBidi for bidirectional text layout. For example, the attacker can construct a crafted text file to be opened in GEdit, or a crafted IRC message to be viewed in HexChat.


fribidi_get_par_embedding_levels_ex (
  /* input */
  const FriBidiCharType *bidi_types,
  const FriBidiBracketType *bracket_types,
  const FriBidiStrIndex len,
  /* input and output */
  FriBidiParType *pbase_dir,
  /* output */
  FriBidiLevel *embedding_levels
)
{
  FriBidiLevel base_level_per_iso_level[FRIBIDI_BIDI_MAX_EXPLICIT_LEVEL];
  FriBidiLevel base_level, max_level = 0;
  FriBidiParType base_dir;
  FriBidiRun *main_run_list = NULL, *explicits_list = NULL, *pp;
  fribidi_boolean status = false;
  int max_iso_level = 0;

  if UNLIKELY
    (!len)
    {
      status = true;
      goto out;
    }

  DBG ("in fribidi_get_par_embedding_levels");

  fribidi_assert (bidi_types);
  fribidi_assert (pbase_dir);
  fribidi_assert (embedding_levels);

  /* Determinate character types */
  {
    /* Get run-length encoded character types */
    main_run_list = run_list_encode_bidi_types (bidi_types, bracket_types, len);
    if UNLIKELY
      (!main_run_list) goto out;
  }

  /* Find base level */
  /* If no strong base_dir was found, resort to the weak direction
     that was passed on input. */
  base_level = FRIBIDI_DIR_TO_LEVEL (*pbase_dir);
  if (!FRIBIDI_IS_STRONG (*pbase_dir))
    /* P2. P3. Search for first strong character and use its direction as
       base direction */
    {
      int valid_isolate_count = 0;
      for_run_list (pp, main_run_list)
        {
          if (RL_TYPE(pp) == FRIBIDI_TYPE_PDI)
            {
              /* Ignore if there is no matching isolate */
              if (valid_isolate_count>0)
                valid_isolate_count--;
            }
          else if (FRIBIDI_IS_ISOLATE(RL_TYPE(pp)))
            valid_isolate_count++;
          else if (valid_isolate_count==0 && FRIBIDI_IS_LETTER (RL_TYPE (pp)))
            {
              base_level = FRIBIDI_DIR_TO_LEVEL (RL_TYPE (pp));
              *pbase_dir = FRIBIDI_LEVEL_TO_DIR (base_level);
              break;
            }
        }
    }
  base_dir = FRIBIDI_LEVEL_TO_DIR (base_level);
  DBG2 ("  base level : %c", fribidi_char_from_level (base_level));
  DBG2 ("  base dir   : %s", fribidi_get_bidi_type_name (base_dir));

  base_level_per_iso_level[0] = base_level;

# if DEBUG
  if UNLIKELY
    (fribidi_debug_status ())
    {
      print_types_re (main_run_list);
    }
# endif	/* DEBUG */

  /* Explicit Levels and Directions */
  DBG ("explicit levels and directions");
  {
    FriBidiLevel level, new_level = 0;
    int isolate_level = 0;
    FriBidiCharType override, new_override;
    FriBidiStrIndex i;
    int stack_size, over_pushed, first_interval;
    int valid_isolate_count = 0;
    int isolate_overflow = 0;
    int isolate = 0; /* The isolate status flag */
    struct
    {
      FriBidiCharType override;	/* only LTR, RTL and ON are valid */
      FriBidiLevel level;
      int isolate;
      int isolate_level;
    } status_stack[FRIBIDI_BIDI_MAX_RESOLVED_LEVELS];
    FriBidiRun temp_link;
    FriBidiRun *run_per_isolate_level[FRIBIDI_BIDI_MAX_RESOLVED_LEVELS];

    memset(run_per_isolate_level, 0, sizeof(run_per_isolate_level[0])
           * FRIBIDI_BIDI_MAX_RESOLVED_LEVELS);

/* explicits_list is a list like main_run_list, that holds the explicit
   codes that are removed from main_run_list, to reinsert them later by
   calling the shadow_run_list.
*/
    explicits_list = new_run_list ();
    if UNLIKELY
      (!explicits_list) goto out;

    /* X1. Begin by setting the current embedding level to the paragraph
       embedding level. Set the directional override status to neutral,
       and directional isolate status to false.

       Process each character iteratively, applying rules X2 through X8.
       Only embedding levels from 0 to 123 are valid in this phase. */

    level = base_level;
    override = FRIBIDI_TYPE_ON;
    /* stack */
    stack_size = 0;
    over_pushed = 0;
    first_interval = 0;
    valid_isolate_count = 0;
    isolate_overflow = 0;

    for_run_list (pp, main_run_list)
    {
      FriBidiCharType this_type = RL_TYPE (pp);
      RL_ISOLATE_LEVEL (pp) = isolate_level;

      if (FRIBIDI_IS_EXPLICIT_OR_BN (this_type))
	{
	  if (FRIBIDI_IS_STRONG (this_type))
	    {			/* LRE, RLE, LRO, RLO */
	      /* 1. Explicit Embeddings */
	      /*   X2. With each RLE, compute the least greater odd
	         embedding level. */
	      /*   X3. With each LRE, compute the least greater even
	         embedding level. */
	      /* 2. Explicit Overrides */
	      /*   X4. With each RLO, compute the least greater odd
	         embedding level. */
	      /*   X5. With each LRO, compute the least greater even
	         embedding level. */
	      new_override = FRIBIDI_EXPLICIT_TO_OVERRIDE_DIR (this_type);
	      for (i = RL_LEN (pp); i; i--)
		{
		  new_level =
		    ((level + FRIBIDI_DIR_TO_LEVEL (this_type) + 2) & ~1) -
		    FRIBIDI_DIR_TO_LEVEL (this_type);
                  isolate = 0;
		  PUSH_STATUS;
		}
	    }
	  else if (this_type == FRIBIDI_TYPE_PDF)
	    {
	      /* 3. Terminating Embeddings and overrides */
	      /*   X7. With each PDF, determine the matching embedding or
	         override code. */
              for (i = RL_LEN (pp); i; i--)
                {
                  if (stack_size && status_stack[stack_size-1].isolate != 0)
                    break;
                  POP_STATUS;
                }
	    }

	  /* X9. Remove all RLE, LRE, RLO, LRO, PDF, and BN codes. */
	  /* Remove element and add it to explicits_list */
	  RL_LEVEL (pp) = FRIBIDI_SENTINEL;
	  temp_link.next = pp->next;
	  move_node_before (pp, explicits_list);
	  pp = &temp_link;
	}
      else if (this_type == FRIBIDI_TYPE_PDI)
        /* X6a. pop the direction of the stack */
        {
          for (i = RL_LEN (pp); i; i--)
            {
              if (isolate_overflow > 0)
                {
                  isolate_overflow--;
                  RL_LEVEL (pp) = level;
                }

              else if (valid_isolate_count > 0)
                {
                  /* Pop away all LRE,RLE,LRO, RLO levels
                     from the stack, as these are implicitly
                     terminated by the PDI */
                  while (stack_size && !status_stack[stack_size-1].isolate)
                    POP_STATUS;
                  over_pushed = 0; /* The PDI resets the overpushed! */
                  POP_STATUS;
                  isolate_level-- ;
                  valid_isolate_count--;
                  RL_LEVEL (pp) = level;
                  RL_ISOLATE_LEVEL (pp) = isolate_level;
                }
              else
                {
                  /* Ignore isolated PDI's by turning them into ON's */
                  RL_TYPE (pp) = FRIBIDI_TYPE_ON;
                  RL_LEVEL (pp) = level;
                }
            }
        }
      else if (FRIBIDI_IS_ISOLATE(this_type))
        {
          /* TBD support RL_LEN > 1 */
          new_override = FRIBIDI_TYPE_ON;
          isolate = 1;
          if (this_type == FRIBIDI_TYPE_LRI)
            new_level = level + 2 - (level%2);
          else if (this_type == FRIBIDI_TYPE_RLI)
            new_level = level + 1 + (level%2);
          else if (this_type == FRIBIDI_TYPE_FSI)
            {
              /* Search for a local strong character until we
                 meet the corresponding PDI or the end of the
                 paragraph */
              FriBidiRun *fsi_pp;
              int isolate_count = 0;
              int fsi_base_level = 0;
              for_run_list (fsi_pp, pp)
                {
                  if (RL_TYPE(fsi_pp) == FRIBIDI_TYPE_PDI)
                    {
                      isolate_count--;
                      if (valid_isolate_count < 0)
                        break;
                    }
                  else if (FRIBIDI_IS_ISOLATE(RL_TYPE(fsi_pp)))
                    isolate_count++;
                  else if (isolate_count==0 && FRIBIDI_IS_LETTER (RL_TYPE (fsi_pp)))
                    {
                      fsi_base_level = FRIBIDI_DIR_TO_LEVEL (RL_TYPE (fsi_pp));
                      break;
                    }
                }

              /* Same behavior like RLI and LRI above */
              if (FRIBIDI_LEVEL_IS_RTL (fsi_base_level))
                new_level = level + 1 + (level%2);
              else
                new_level = level + 2 - (level%2);
            }

	  RL_LEVEL (pp) = level;
          RL_ISOLATE_LEVEL (pp) = isolate_level++;
          base_level_per_iso_level[isolate_level] = new_level;

	  if (!FRIBIDI_IS_NEUTRAL (override))
	    RL_TYPE (pp) = override;

          if (new_level <= FRIBIDI_BIDI_MAX_EXPLICIT_LEVEL)
            {
              valid_isolate_count++;
              PUSH_STATUS;
              level = new_level;
            }
          else
            isolate_overflow += 1;
        }
      else if (this_type == FRIBIDI_TYPE_BS)
	{
	  /* X8. All explicit directional embeddings and overrides are
	     completely terminated at the end of each paragraph. Paragraph
	     separators are not included in the embedding. */
	  break;
	}
      else
	{
	  /* X6. For all types besides RLE, LRE, RLO, LRO, and PDF:
	     a. Set the level of the current character to the current
	     embedding level.
	     b. Whenever the directional override status is not neutral,
	     reset the current character type to the directional override
	     status. */
	  RL_LEVEL (pp) = level;
	  if (!FRIBIDI_IS_NEUTRAL (override))
	    RL_TYPE (pp) = override;
	}
    }

    /* Build the isolate_level connections */
    for_run_list (pp, main_run_list)
    {
      int isolate_level = RL_ISOLATE_LEVEL (pp);
      if (run_per_isolate_level[isolate_level])
        {
          run_per_isolate_level[isolate_level]->next_isolate = pp;
          pp->prev_isolate = run_per_isolate_level[isolate_level];
        }
      run_per_isolate_level[isolate_level] = pp;
    }

    /* Implementing X8. It has no effect on a single paragraph! */
    level = base_level;
    override = FRIBIDI_TYPE_ON;
    stack_size = 0;
    over_pushed = 0;
  }
  /* X10. The remaining rules are applied to each run of characters at the
     same level. For each run, determine the start-of-level-run (sor) and
     end-of-level-run (eor) type, either L or R. This depends on the
     higher of the two levels on either side of the boundary (at the start
     or end of the paragraph, the level of the 'other' run is the base
     embedding level). If the higher level is odd, the type is R, otherwise
     it is L. */
  /* Resolving Implicit Levels can be done out of X10 loop, so only change
     of Resolving Weak Types and Resolving Neutral Types is needed. */

  compact_list (main_run_list);

# if DEBUG
  if UNLIKELY
    (fribidi_debug_status ())
    {
      print_types_re (main_run_list);
      print_bidi_string (bidi_types, len);
      print_resolved_levels (main_run_list);
      print_resolved_types (main_run_list);
    }
# endif	/* DEBUG */

  /* 4. Resolving weak types. Also calculate the maximum isolate level */
  max_iso_level = 0;
  DBG ("resolving weak types");
  {
    int last_strong_stack[FRIBIDI_BIDI_MAX_RESOLVED_LEVELS];
    FriBidiCharType prev_type_orig;
    fribidi_boolean w4;

    last_strong_stack[0] = base_dir;

    for_run_list (pp, main_run_list)
    {
      register FriBidiCharType prev_type, this_type, next_type;
      FriBidiRun *ppp_prev, *ppp_next;
      int iso_level;

      ppp_prev = get_adjacent_run(pp, false, false);
      ppp_next = get_adjacent_run(pp, true, false);

      this_type = RL_TYPE (pp);
      iso_level = RL_ISOLATE_LEVEL(pp);

      if (iso_level > max_iso_level)
        max_iso_level = iso_level;

      if (RL_LEVEL(ppp_prev) == RL_LEVEL(pp))
        prev_type = RL_TYPE(ppp_prev);
      else
        prev_type = FRIBIDI_LEVEL_TO_DIR(MAX(RL_LEVEL(ppp_prev), RL_LEVEL(pp)));

      if (RL_LEVEL(ppp_next) == RL_LEVEL(pp))
        next_type = RL_TYPE(ppp_next);
      else
        next_type = FRIBIDI_LEVEL_TO_DIR(MAX(RL_LEVEL(ppp_next), RL_LEVEL(pp)));

      if (FRIBIDI_IS_STRONG (prev_type))
	last_strong_stack[iso_level] = prev_type;

      /* W1. NSM
         Examine each non-spacing mark (NSM) in the level run, and change the
         type of the NSM to the type of the previous character. If the NSM
         is at the start of the level run, it will get the type of sor. */
      /* Implementation note: it is important that if the previous character
         is not sor, then we should merge this run with the previous,
         because of rules like W5, that we assume all of a sequence of
         adjacent ETs are in one FriBidiRun. */
      if (this_type == FRIBIDI_TYPE_NSM)
	{
          /* New rule in Unicode 6.3 */
          if (FRIBIDI_IS_ISOLATE (RL_TYPE (pp->prev)))
              RL_TYPE(pp) = FRIBIDI_TYPE_ON;

	  if (RL_LEVEL (ppp_prev) == RL_LEVEL (pp))
            {
              if (ppp_prev == pp->prev)
                pp = merge_with_prev (pp);
            }
	  else
	    RL_TYPE (pp) = prev_type;

	  if (prev_type == next_type && RL_LEVEL (pp) == RL_LEVEL (pp->next))
	    {
              if (ppp_next == pp->next)
                pp = merge_with_prev (pp->next);
	    }
	  continue;		/* As we know the next condition cannot be true. */
	}

      /* W2: European numbers. */
      if (this_type == FRIBIDI_TYPE_EN && last_strong_stack[iso_level] == FRIBIDI_TYPE_AL)
	{
	  RL_TYPE (pp) = FRIBIDI_TYPE_AN;

	  /* Resolving dependency of loops for rules W1 and W2, so we
	     can merge them in one loop. */
	  if (next_type == FRIBIDI_TYPE_NSM)
	    RL_TYPE (ppp_next) = FRIBIDI_TYPE_AN;
	}
    }

    last_strong_stack[0] = base_dir;

    /* Resolving dependency of loops for rules W4 and W5, W5 may
       want to prevent W4 to take effect in the next turn, do this
       through "w4". */
    w4 = true;
    /* Resolving dependency of loops for rules W4 and W5 with W7,
       W7 may change an EN to L but it sets the prev_type_orig if needed,
       so W4 and W5 in next turn can still do their works. */
    prev_type_orig = FRIBIDI_TYPE_ON;

    /* Each isolate level has its own memory of the last strong character */
    for_run_list (pp, main_run_list)
    {
      register FriBidiCharType prev_type, this_type, next_type;
      int iso_level;
      FriBidiRun *ppp_prev, *ppp_next;

      this_type = RL_TYPE (pp);
      iso_level = RL_ISOLATE_LEVEL(pp);

      ppp_prev = get_adjacent_run(pp, false, false);
      ppp_next = get_adjacent_run(pp, true, false);

      if (RL_LEVEL(ppp_prev) == RL_LEVEL(pp))
        prev_type = RL_TYPE(ppp_prev);
      else
        prev_type = FRIBIDI_LEVEL_TO_DIR(MAX(RL_LEVEL(ppp_prev), RL_LEVEL(pp)));

      if (RL_LEVEL(ppp_next) == RL_LEVEL(pp))
        next_type = RL_TYPE(ppp_next);
      else
        next_type = FRIBIDI_LEVEL_TO_DIR(MAX(RL_LEVEL(ppp_next), RL_LEVEL(pp)));

      if (FRIBIDI_IS_STRONG (prev_type))
	last_strong_stack[iso_level] = prev_type;

      /* W2 ??? */

      /* W3: Change ALs to R. */
      if (this_type == FRIBIDI_TYPE_AL)
	{
	  RL_TYPE (pp) = FRIBIDI_TYPE_RTL;
	  w4 = true;
	  prev_type_orig = FRIBIDI_TYPE_ON;
	  continue;
	}

      /* W4. A single european separator changes to a european number.
         A single common separator between two numbers of the same type
         changes to that type. */
      if (w4
	  && RL_LEN (pp) == 1 && FRIBIDI_IS_ES_OR_CS (this_type)
	  && FRIBIDI_IS_NUMBER (prev_type_orig)
	  && prev_type_orig == next_type
	  && (prev_type_orig == FRIBIDI_TYPE_EN
	      || this_type == FRIBIDI_TYPE_CS))
	{
	  RL_TYPE (pp) = prev_type;
	  this_type = RL_TYPE (pp);
	}
      w4 = true;

      /* W5. A sequence of European terminators adjacent to European
         numbers changes to All European numbers. */
      if (this_type == FRIBIDI_TYPE_ET
	  && (prev_type_orig == FRIBIDI_TYPE_EN
	      || next_type == FRIBIDI_TYPE_EN))
	{
	  RL_TYPE (pp) = FRIBIDI_TYPE_EN;
	  w4 = false;
	  this_type = RL_TYPE (pp);
	}

      /* W6. Otherwise change separators and terminators to other neutral. */
      if (FRIBIDI_IS_NUMBER_SEPARATOR_OR_TERMINATOR (this_type))
	RL_TYPE (pp) = FRIBIDI_TYPE_ON;

      /* W7. Change european numbers to L. */
      if (this_type == FRIBIDI_TYPE_EN && last_strong_stack[iso_level] == FRIBIDI_TYPE_LTR)
	{
	  RL_TYPE (pp) = FRIBIDI_TYPE_LTR;
	  prev_type_orig = (RL_LEVEL (pp) == RL_LEVEL (pp->next) ?
			    FRIBIDI_TYPE_EN : FRIBIDI_TYPE_ON);
	}
      else
	prev_type_orig = PREV_TYPE_OR_SOR (pp->next);
    }
  }

  compact_neutrals (main_run_list);

# if DEBUG
  if UNLIKELY
    (fribidi_debug_status ())
    {
      print_resolved_levels (main_run_list);
      print_resolved_types (main_run_list);
    }
# endif	/* DEBUG */

  /* 5. Resolving Neutral Types */

  DBG ("resolving neutral types - N0");
  {
    /*  BD16 - Build list of all pairs*/
    int num_iso_levels = max_iso_level + 1;
    FriBidiPairingNode *pairing_nodes = NULL;
    FriBidiRun *local_bracket_stack[FRIBIDI_BIDI_MAX_EXPLICIT_LEVEL][LOCAL_BRACKET_SIZE];
    FriBidiRun **bracket_stack[FRIBIDI_BIDI_MAX_EXPLICIT_LEVEL];
    int bracket_stack_size[FRIBIDI_BIDI_MAX_EXPLICIT_LEVEL];
    int last_level = RL_LEVEL(main_run_list);
    int last_iso_level = 0;

    memset(bracket_stack, 0, sizeof(bracket_stack[0])*num_iso_levels);
    memset(bracket_stack_size, 0, sizeof(bracket_stack_size[0])*num_iso_levels);

    /* populate the bracket_size. The first LOCAL_BRACKET_SIZE entries
       of the stack are one the stack. Allocate the rest of the entries.
     */
    {
      int iso_level;
      for (iso_level=0; iso_level < LOCAL_BRACKET_SIZE; iso_level++)
        bracket_stack[iso_level] = local_bracket_stack[iso_level];

      for (iso_level=LOCAL_BRACKET_SIZE; iso_level < num_iso_levels; iso_level++)
        bracket_stack[iso_level] = fribidi_malloc (sizeof (bracket_stack[0])
                                                       * FRIBIDI_BIDI_MAX_NESTED_BRACKET_PAIRS);
    }

    /* Build the bd16 pair stack. */
    for_run_list (pp, main_run_list)
      {
        int level = RL_LEVEL(pp);
        int iso_level = RL_ISOLATE_LEVEL(pp);
        FriBidiBracketType brack_prop = RL_BRACKET_TYPE(pp);

        /* Interpret the isolating run sequence as such that they
           end at a change in the level, unless the iso_level has been
           raised. */
        if (level != last_level && last_iso_level == iso_level)
          bracket_stack_size[last_iso_level] = 0;

        if (brack_prop!= FRIBIDI_NO_BRACKET)
          {
            if (FRIBIDI_IS_BRACKET_OPEN(brack_prop))
              {
                if (bracket_stack_size[iso_level]==FRIBIDI_BIDI_MAX_NESTED_BRACKET_PAIRS)
                  break;

                /* push onto the pair stack */
                bracket_stack[iso_level][bracket_stack_size[iso_level]++] = pp;
              }
            else
              {
                int stack_idx = bracket_stack_size[iso_level] - 1;
                while (stack_idx >= 0)
                  {
                    FriBidiBracketType se_brack_prop = RL_BRACKET_TYPE(bracket_stack[iso_level][stack_idx]);
                    if (FRIBIDI_BRACKET_ID(se_brack_prop) == FRIBIDI_BRACKET_ID(brack_prop))
                      {
                        bracket_stack_size[iso_level] = stack_idx;

                        pairing_nodes = pairing_nodes_push(pairing_nodes,
                                                           bracket_stack[iso_level][stack_idx],
                                                           pp);
                        break;
                    }
                    stack_idx--;
                  }
              }
          }
        last_level = level;
        last_iso_level = iso_level;
      }

    /* The list must now be sorted for the next algo to work! */
    sort_pairing_nodes(&pairing_nodes);

# if DEBUG
    if UNLIKELY
    (fribidi_debug_status ())
      {
        print_pairing_nodes (pairing_nodes);
      }
# endif	/* DEBUG */

    /* Start the N0 */
    {
      FriBidiPairingNode *ppairs = pairing_nodes;
      while (ppairs)
        {
          int iso_level = ppairs->open->isolate_level;
          int embedding_level = base_level_per_iso_level[iso_level];

          /* Find matching strong. */
          fribidi_boolean found = false;
          FriBidiRun *ppn;
          for (ppn = ppairs->open; ppn!= ppairs->close; ppn = ppn->next)
            {
              FriBidiCharType this_type = RL_TYPE_AN_EN_AS_RTL(ppn);

              /* Calculate level like in resolve implicit levels below to prevent
                 embedded levels not to match the base_level */
              int this_level = RL_LEVEL (ppn) +
                (FRIBIDI_LEVEL_IS_RTL (RL_LEVEL(ppn)) ^ FRIBIDI_DIR_TO_LEVEL (this_type));

              /* N0b */
              if (FRIBIDI_IS_STRONG (this_type) && this_level == embedding_level)
                {
                  RL_TYPE(ppairs->open) = RL_TYPE(ppairs->close) = this_level%2 ? FRIBIDI_TYPE_RTL : FRIBIDI_TYPE_LTR;
                  found = true;
                  break;
                }
            }

          /* N0c */
          /* Search for any strong type preceding and within the bracket pair */
          if (!found)
            {
              /* Search for a preceding strong */
              int prec_strong_level = embedding_level; /* TBDov! Extract from Isolate level in effect */
              int iso_level = RL_ISOLATE_LEVEL(ppairs->open);
              for (ppn = ppairs->open->prev; ppn->type != FRIBIDI_TYPE_SENTINEL; ppn=ppn->prev)
                {
                  FriBidiCharType this_type = RL_TYPE_AN_EN_AS_RTL(ppn);
                  if (FRIBIDI_IS_STRONG (this_type) && RL_ISOLATE_LEVEL(ppn) == iso_level)
                    {
                      prec_strong_level = RL_LEVEL (ppn) +
                        (FRIBIDI_LEVEL_IS_RTL (RL_LEVEL(ppn)) ^ FRIBIDI_DIR_TO_LEVEL (this_type));

                      break;
                    }
                }

              for (ppn = ppairs->open; ppn!= ppairs->close; ppn = ppn->next)
                {
                  FriBidiCharType this_type = RL_TYPE_AN_EN_AS_RTL(ppn);
                  if (FRIBIDI_IS_STRONG (this_type) && RL_ISOLATE_LEVEL(ppn) == iso_level)
                    {
                      /* By constraint this is opposite the embedding direction,
                         since we did not match the N0b rule. We must now
                         compare with the preceding strong to establish whether
                         to apply N0c1 (opposite) or N0c2 embedding */
                      RL_TYPE(ppairs->open) = RL_TYPE(ppairs->close) = prec_strong_level % 2 ? FRIBIDI_TYPE_RTL : FRIBIDI_TYPE_LTR;
                      RL_LEVEL(ppairs->open) = RL_LEVEL(ppairs->close) = prec_strong_level;
                      found = true;
                      break;
                    }
                }
            }

          ppairs = ppairs->next;
        }

      free_pairing_nodes(pairing_nodes);

      if (num_iso_levels >= LOCAL_BRACKET_SIZE)
        {
          int i;
          /* Only need to free the non static members */
          for (i=LOCAL_BRACKET_SIZE; i<num_iso_levels; i++)
            fribidi_free(bracket_stack[i]);
        }

      /* Remove the bracket property and re-compact */
      {
        const FriBidiBracketType NoBracket = FRIBIDI_NO_BRACKET;
        for_run_list (pp, main_run_list)
          pp->bracket_type = NoBracket;
        compact_list (main_run_list);
      }
    }

# if DEBUG
  if UNLIKELY
    (fribidi_debug_status ())
    {
      print_resolved_levels (main_run_list);
      print_resolved_types (main_run_list);
    }
# endif	/* DEBUG */
  }

  DBG ("resolving neutral types - N1+N2");
  {
    for_run_list (pp, main_run_list)
    {
      FriBidiCharType prev_type, this_type, next_type;
      FriBidiRun *ppp_prev, *ppp_next;

      ppp_prev = get_adjacent_run(pp, false, false);
      ppp_next = get_adjacent_run(pp, true, false);

      /* "European and Arabic numbers are treated as though they were R"
         FRIBIDI_CHANGE_NUMBER_TO_RTL does this. */
      this_type = FRIBIDI_CHANGE_NUMBER_TO_RTL (RL_TYPE (pp));

      if (RL_LEVEL(ppp_prev) == RL_LEVEL(pp))
        prev_type = FRIBIDI_CHANGE_NUMBER_TO_RTL (RL_TYPE(ppp_prev));
      else
        prev_type = FRIBIDI_LEVEL_TO_DIR(MAX(RL_LEVEL(ppp_prev), RL_LEVEL(pp)));

      if (RL_LEVEL(ppp_next) == RL_LEVEL(pp))
        next_type = FRIBIDI_CHANGE_NUMBER_TO_RTL (RL_TYPE(ppp_next));
      else
        next_type = FRIBIDI_LEVEL_TO_DIR(MAX(RL_LEVEL(ppp_next), RL_LEVEL(pp)));

      if (FRIBIDI_IS_NEUTRAL (this_type))
	RL_TYPE (pp) = (prev_type == next_type) ?
	  /* N1. */ prev_type :
	  /* N2. */ FRIBIDI_EMBEDDING_DIRECTION (pp);
    }
  }

  compact_list (main_run_list);

# if DEBUG
  if UNLIKELY
    (fribidi_debug_status ())
    {
      print_resolved_levels (main_run_list);
      print_resolved_types (main_run_list);
    }
# endif	/* DEBUG */

  /* 6. Resolving implicit levels */
  DBG ("resolving implicit levels");
  {
    max_level = base_level;

    for_run_list (pp, main_run_list)
    {
      FriBidiCharType this_type;
      int level;

      this_type = RL_TYPE (pp);
      level = RL_LEVEL (pp);

      /* I1. Even */
      /* I2. Odd */
      if (FRIBIDI_IS_NUMBER (this_type))
	RL_LEVEL (pp) = (level + 2) & ~1;
      else
	RL_LEVEL (pp) =
	  level +
	  (FRIBIDI_LEVEL_IS_RTL (level) ^ FRIBIDI_DIR_TO_LEVEL (this_type));

      if (RL_LEVEL (pp) > max_level)
	max_level = RL_LEVEL (pp);
    }
  }

  compact_list (main_run_list);

# if DEBUG
  if UNLIKELY
    (fribidi_debug_status ())
    {
      print_bidi_string (bidi_types, len);
      print_resolved_levels (main_run_list);
      print_resolved_types (main_run_list);
    }
# endif	/* DEBUG */

/* Reinsert the explicit codes & BN's that are already removed, from the
   explicits_list to main_run_list. */
  DBG ("reinserting explicit codes");
  if UNLIKELY
    (explicits_list->next != explicits_list)
    {
      register FriBidiRun *p;
      register fribidi_boolean stat =
	shadow_run_list (main_run_list, explicits_list, true);
      explicits_list = NULL;
      if UNLIKELY
	(!stat) goto out;

      /* Set level of inserted explicit chars to that of their previous
       * char, such that they do not affect reordering. */
      p = main_run_list->next;
      if (p != main_run_list && p->level == FRIBIDI_SENTINEL)
	p->level = base_level;
      for_run_list (p, main_run_list) if (p->level == FRIBIDI_SENTINEL)
	p->level = p->prev->level;
    }

# if DEBUG
  if UNLIKELY
    (fribidi_debug_status ())
    {
      print_types_re (main_run_list);
      print_resolved_levels (main_run_list);
      print_resolved_types (main_run_list);
    }
# endif	/* DEBUG */

  DBG ("reset the embedding levels, 1, 2, 3.");
  {
    register int j, state, pos;
    register FriBidiCharType char_type;
    register FriBidiRun *p, *q, *list;

    /* L1. Reset the embedding levels of some chars:
       1. segment separators,
       2. paragraph separators,
       3. any sequence of whitespace characters preceding a segment
          separator or paragraph separator, and
       4. any sequence of whitespace characters and/or isolate formatting
          characters at the end of the line.
       ... (to be continued in fribidi_reorder_line()). */
    list = new_run_list ();
    if UNLIKELY
      (!list) goto out;
    q = list;
    state = 1;
    pos = len - 1;
    for (j = len - 1; j >= -1; j--)
      {
	/* close up the open link at the end */
	if (j >= 0)
	  char_type = bidi_types[j];
	else
	  char_type = FRIBIDI_TYPE_ON;
	if (!state && FRIBIDI_IS_SEPARATOR (char_type))
	  {
	    state = 1;
	    pos = j;
	  }
	else if (state &&
                 !(FRIBIDI_IS_EXPLICIT_OR_SEPARATOR_OR_BN_OR_WS(char_type)
                   || FRIBIDI_IS_ISOLATE(char_type)))
	  {
	    state = 0;
	    p = new_run ();
	    if UNLIKELY
	      (!p)
	      {
		free_run_list (list);
		goto out;
	      }
	    p->pos = j + 1;
	    p->len = pos - j;
	    p->type = base_dir;
	    p->level = base_level;
	    move_node_before (p, q);
	    q = p;
	  }
      }
    if UNLIKELY
      (!shadow_run_list (main_run_list, list, false)) goto out;
  }

# if DEBUG
  if UNLIKELY
    (fribidi_debug_status ())
    {
      print_types_re (main_run_list);
      print_resolved_levels (main_run_list);
      print_resolved_types (main_run_list);
    }
# endif	/* DEBUG */

  {
    FriBidiStrIndex pos = 0;
    for_run_list (pp, main_run_list)
    {
      register FriBidiStrIndex l;
      register FriBidiLevel level = pp->level;
      for (l = pp->len; l; l--)
	embedding_levels[pos++] = level;
    }
  }

  status = true;

out:
  DBG ("leaving fribidi_get_par_embedding_levels");

  if (main_run_list)
    free_run_list (main_run_list);
  if UNLIKELY
    (explicits_list) free_run_list (explicits_list);

  return status ? max_level + 1 : 0;
}


jbd2: fix use-after-free of transaction_t race

jbd2_journal_wait_updates() is called with j_state_lock held. But if
there is a commit in progress, then this transaction might get committed
and freed via jbd2_journal_commit_transaction() ->
jbd2_journal_free_transaction(), when we release j_state_lock.
So check for journal->j_running_transaction everytime we release and
acquire j_state_lock to avoid use-after-free issue.

Link: https://lore.kernel.org/r/948c2fed518ae739db6a8f7f83f1d58b504f87d0.1644497105.git.ritesh.list@gmail.com
Fixes: 4f98186848707f53 ("jbd2: refactor wait logic for transaction updates into a common function")
Cc: stable@kernel.org
Reported-and-tested-by: syzbot+afa2ca5171d93e44b348@syzkaller.appspotmail.com
Reviewed-by: Jan Kara <jack@suse.cz>
Signed-off-by: Ritesh Harjani <riteshh@linux.ibm.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>

void jbd2_journal_wait_updates(journal_t *journal)
{
	transaction_t *commit_transaction = journal->j_running_transaction;

	if (!commit_transaction)
		return;

	spin_lock(&commit_transaction->t_handle_lock);
	while (atomic_read(&commit_transaction->t_updates)) {
		DEFINE_WAIT(wait);

		prepare_to_wait(&journal->j_wait_updates, &wait,
					TASK_UNINTERRUPTIBLE);
		if (atomic_read(&commit_transaction->t_updates)) {
			spin_unlock(&commit_transaction->t_handle_lock);
			write_unlock(&journal->j_state_lock);
			schedule();
			write_lock(&journal->j_state_lock);
			spin_lock(&commit_transaction->t_handle_lock);
		}
		finish_wait(&journal->j_wait_updates, &wait);
	}
	spin_unlock(&commit_transaction->t_handle_lock);
}

jbd2_journal_wait_updates in fs/jbd2/transaction.c in the Linux kernel before 5.17.1 has a use-after-free caused by a transaction_t race condition.


void jbd2_journal_wait_updates(journal_t *journal)
{
	DEFINE_WAIT(wait);

	while (1) {
		/*
		 * Note that the running transaction can get freed under us if
		 * this transaction is getting committed in
		 * jbd2_journal_commit_transaction() ->
		 * jbd2_journal_free_transaction(). This can only happen when we
		 * release j_state_lock -> schedule() -> acquire j_state_lock.
		 * Hence we should everytime retrieve new j_running_transaction
		 * value (after j_state_lock release acquire cycle), else it may
		 * lead to use-after-free of old freed transaction.
		 */
		transaction_t *transaction = journal->j_running_transaction;

		if (!transaction)
			break;

		spin_lock(&transaction->t_handle_lock);
		prepare_to_wait(&journal->j_wait_updates, &wait,
				TASK_UNINTERRUPTIBLE);
		if (!atomic_read(&transaction->t_updates)) {
			spin_unlock(&transaction->t_handle_lock);
			finish_wait(&journal->j_wait_updates, &wait);
			break;
		}
		spin_unlock(&transaction->t_handle_lock);
		write_unlock(&journal->j_state_lock);
		schedule();
		finish_wait(&journal->j_wait_updates, &wait);
		write_lock(&journal->j_state_lock);
	}
}


Bug 790853 - (CVE-2017-17787) heap overread in psp importer.

As any external data, we have to check that strings being read at fixed
length are properly nul-terminated.

read_creator_block (FILE     *f,
                    gint      image_ID,
                    guint     total_len,
                    PSPimage *ia)
{
  long          data_start;
  guchar        buf[4];
  guint16       keyword;
  guint32       length;
  gchar        *string;
  gchar        *title = NULL, *artist = NULL, *copyright = NULL, *description = NULL;
  guint32       dword;
  guint32       __attribute__((unused))cdate = 0;
  guint32       __attribute__((unused))mdate = 0;
  guint32       __attribute__((unused))appid;
  guint32       __attribute__((unused))appver;
  GString      *comment;
  GimpParasite *comment_parasite;

  data_start = ftell (f);
  comment = g_string_new (NULL);

  while (ftell (f) < data_start + total_len)
    {
      if (fread (buf, 4, 1, f) < 1
          || fread (&keyword, 2, 1, f) < 1
          || fread (&length, 4, 1, f) < 1)
        {
          g_message ("Error reading creator keyword chunk");
          return -1;
        }
      if (memcmp (buf, "~FL\0", 4) != 0)
        {
          g_message ("Invalid keyword chunk header");
          return -1;
        }
      keyword = GUINT16_FROM_LE (keyword);
      length = GUINT32_FROM_LE (length);
      switch (keyword)
        {
        case PSP_CRTR_FLD_TITLE:
        case PSP_CRTR_FLD_ARTIST:
        case PSP_CRTR_FLD_CPYRGHT:
        case PSP_CRTR_FLD_DESC:
          string = g_malloc (length + 1);
          if (fread (string, length, 1, f) < 1)
            {
              g_message ("Error reading creator keyword data");
              g_free (string);
              return -1;
            }
          switch (keyword)
            {
            case PSP_CRTR_FLD_TITLE:
              g_free (title); title = string; break;
            case PSP_CRTR_FLD_ARTIST:
              g_free (artist); artist = string; break;
            case PSP_CRTR_FLD_CPYRGHT:
              g_free (copyright); copyright = string; break;
            case PSP_CRTR_FLD_DESC:
              g_free (description); description = string; break;
            default:
              g_free (string);
            }
          break;
        case PSP_CRTR_FLD_CRT_DATE:
        case PSP_CRTR_FLD_MOD_DATE:
        case PSP_CRTR_FLD_APP_ID:
        case PSP_CRTR_FLD_APP_VER:
          if (fread (&dword, 4, 1, f) < 1)
            {
              g_message ("Error reading creator keyword data");
              return -1;
            }
          switch (keyword)
            {
            case PSP_CRTR_FLD_CRT_DATE:
              cdate = dword; break;
            case PSP_CRTR_FLD_MOD_DATE:
              mdate = dword; break;
            case PSP_CRTR_FLD_APP_ID:
              appid = dword; break;
            case PSP_CRTR_FLD_APP_VER:
              appver = dword; break;
            }
          break;
        default:
          if (try_fseek (f, length, SEEK_CUR) < 0)
            {
              return -1;
            }
          break;
        }
    }

  if (title)
    {
      g_string_append (comment, title);
      g_free (title);
      g_string_append (comment, "\n");
    }
  if (artist)
    {
      g_string_append (comment, artist);
      g_free (artist);
      g_string_append (comment, "\n");
    }
  if (copyright)
    {
      g_string_append (comment, "Copyright ");
      g_string_append (comment, copyright);
      g_free (copyright);
      g_string_append (comment, "\n");
    }
  if (description)
    {
      g_string_append (comment, description);
      g_free (description);
      g_string_append (comment, "\n");
    }
  if (comment->len > 0)
    {
      comment_parasite = gimp_parasite_new ("gimp-comment",
                                            GIMP_PARASITE_PERSISTENT,
                                            strlen (comment->str) + 1,
                                            comment->str);
      gimp_image_attach_parasite (image_ID, comment_parasite);
      gimp_parasite_free (comment_parasite);
    }

  g_string_free (comment, FALSE);

  return 0;
}

In GIMP 2.8.22, there is a heap-based buffer over-read in read_creator_block in plug-ins/common/file-psp.c.