Skip to content

Commit 13fb9e3

Browse files
committed
Feature: libcrmcommon: decode_transition_magic() validates more strictly
Technically this changes the behavior of a public API function. * We now reject transition magic strings that begin with whitespace. * We now reject transition magic strings whose op_status or op_rc field begins with a plus sign. These fields must now consist of an optional minus sign followed by digits. * We now reject transition magic strings whose op_status or op_rc field overflows the range of an int. * We now preserve any whitespace at the end of a transition magic string. These are all side effects of replacing the sscanf() calls with a regex match and explicit integer parsing. Signed-off-by: Reid Wahl <nrwahl@protonmail.com>
1 parent 6f791c6 commit 13fb9e3

1 file changed

Lines changed: 36 additions & 24 deletions

File tree

lib/common/actions.c

Lines changed: 36 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -386,50 +386,62 @@ pcmk__notify_key(const char *rsc_id, const char *notify_type,
386386
* for freeing the memory for *uuid using free().
387387
*/
388388
gboolean
389-
decode_transition_magic(const char *magic, char **uuid, int *transition_id, int *action_id,
390-
int *op_status, int *op_rc, int *target_rc)
389+
decode_transition_magic(const char *magic, char **uuid, int *transition_id,
390+
int *action_id, int *op_status, int *op_rc,
391+
int *target_rc)
391392
{
392-
int res = 0;
393-
char *key = NULL;
393+
GRegex *regex = NULL;
394+
GMatchInfo *match_info = NULL;
395+
char **matches = NULL;
396+
397+
long long status_ll = 0;
398+
long long rc_ll = 0;
394399
bool result = false;
395-
int local_op_status = -1;
396-
int local_op_rc = -1;
397400

398401
CRM_CHECK(magic != NULL, goto done);
399402

400-
#ifdef HAVE_SSCANF_M
401-
res = sscanf(magic, "%d:%d;%ms", &local_op_status, &local_op_rc, &key);
402-
#else
403-
// magic must have >=4 other characters
404-
key = pcmk__assert_alloc(strlen(magic) - 3, sizeof(char));
405-
res = sscanf(magic, "%d:%d;%s", &local_op_status, &local_op_rc, key);
406-
#endif
407-
if (res == EOF) {
408-
pcmk__err("Could not decode transition information '%s': %s", magic,
409-
pcmk_rc_str(errno));
403+
regex = g_regex_new("^(-?\\d+):(-?\\d+);(.*)$", 0, 0, NULL);
404+
pcmk__assert(regex != NULL);
405+
406+
if (!g_regex_match(regex, magic, 0, &match_info)) {
407+
pcmk__err("Could not decode transition information '%s': does not "
408+
"match pattern 'STATUS:RC;KEY'", magic);
409+
goto done;
410+
}
411+
412+
matches = g_match_info_fetch_all(match_info);
413+
414+
if ((pcmk__scan_ll(matches[1], &status_ll, 0) != pcmk_rc_ok)
415+
|| (status_ll < INT_MIN) || (status_ll > INT_MAX)) {
416+
417+
pcmk__err("Could not decode transition information '%s': op status "
418+
"'%s' is not a valid int", magic, matches[1]);
410419
goto done;
411420
}
412421

413-
if (res < 3) {
414-
pcmk__warn("Transition information '%s' incomplete (%d of 3 expected "
415-
"items)",
416-
magic, res);
422+
if ((pcmk__scan_ll(matches[2], &rc_ll, 0) != pcmk_rc_ok)
423+
|| (rc_ll < INT_MIN) || (rc_ll > INT_MAX)) {
424+
425+
pcmk__err("Could not decode transition information '%s': op rc '%s' is "
426+
"not a valid int", magic, matches[2]);
417427
goto done;
418428
}
419429

420430
if (op_status != NULL) {
421-
*op_status = local_op_status;
431+
*op_status = status_ll;
422432
}
423433

424434
if (op_rc != NULL) {
425-
*op_rc = local_op_rc;
435+
*op_rc = rc_ll;
426436
}
427437

428-
result = decode_transition_key(key, uuid, transition_id, action_id,
438+
result = decode_transition_key(matches[3], uuid, transition_id, action_id,
429439
target_rc);
430440

431441
done:
432-
free(key);
442+
g_regex_unref(regex);
443+
g_match_info_unref(match_info);
444+
g_strfreev(matches);
433445
return result;
434446
}
435447

0 commit comments

Comments
 (0)