acme-client(1): correctly re-alloc json tokens

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

acme-client(1): correctly re-alloc json tokens

Florian Obser-2
Renaud Allard reported that since switching to the v02 API renewal of
a particular cert with a bunch of subject alt names failed with "bad
json".

Turns out Let's Encrypt's response to the order request contained more
than 128 json tokens and the reallocation code path in json_parse()
ran for the first time ever. This could also be triggered with the v01
api, just add enough alt names.

What's going on is that the parser tells us that it ran out of free
tokens, we alocated twice the amount of tokens, tossed the old ones
and then tell the parser to please continue where it left of.

But for this to work out we need to preserve and pass in the already
parsed tokens.

OK?

diff --git json.c json.c
index 471a5cea8de..4fbc7adb859 100644
--- json.c
+++ json.c
@@ -552,27 +552,30 @@ json_parse(const char *buf, size_t sz)
 {
  struct jsmnn *n;
  jsmn_parser p;
- jsmntok_t *tok;
+ jsmntok_t *tok, *ntok;
  int r;
  size_t tokcount;
 
  jsmn_init(&p);
  tokcount = 128;
 
- /* Do this until we don't need any more tokens. */
-again:
- tok = calloc(tokcount, sizeof(jsmntok_t));
- if (tok == NULL) {
+ if ((tok = calloc(tokcount, sizeof(jsmntok_t))) == NULL) {
  warn("calloc");
  return NULL;
  }
 
+ /* Do this until we don't need any more tokens. */
+again:
  /* Actually try to parse the JSON into the tokens. */
-
  r = jsmn_parse(&p, buf, sz, tok, tokcount);
  if (r < 0 && r == JSMN_ERROR_NOMEM) {
+ if ((ntok = recallocarray(tok, tokcount, tokcount * 2, sizeof(jsmntok_t))) == NULL) {
+ warn("calloc");
+ free(tok);
+ return NULL;
+ }
+ tok = ntok;
  tokcount *= 2;
- free(tok);
  goto again;
  } else if (r < 0) {
  warnx("jsmn_parse: %d", r);


--
I'm not entirely sure you are real.